- 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/version.h
include/fennec/core/system.h
@@ -150,12 +149,14 @@ fennec_add_sources(
include/fennec/lang/declval.h
include/fennec/lang/function.h
include/fennec/lang/hashing.h
include/fennec/lang/integer.h
include/fennec/lang/intrinsics.h
include/fennec/lang/limits.h
include/fennec/lang/numeric_transforms.h
include/fennec/lang/metasequences.h
include/fennec/lang/ranges.h
include/fennec/lang/static_constructor.h
include/fennec/lang/system.h
include/fennec/lang/type_identity.h
include/fennec/lang/type_operators.h
include/fennec/lang/type_sequences.h
@@ -163,7 +164,6 @@ fennec_add_sources(
include/fennec/lang/type_transforms.h
include/fennec/lang/types.h
include/fennec/lang/utility.h
include/fennec/lang/integer.h
include/fennec/lang/assert.h source/lang/assert.cpp
@@ -179,14 +179,15 @@ fennec_add_sources(
# RTTI =================================================================================================================
include/fennec/rtti/typeid.h
include/fennec/rtti/type_data.h
include/fennec/rtti/type.h
include/fennec/rtti/enable.h
include/fennec/rtti/forward.h
include/fennec/rtti/typelist.h
include/fennec/rtti/type_registry.h
include/fennec/rtti/enable.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
@@ -268,6 +269,7 @@ fennec_add_sources(
include/fennec/string/locale.h
include/fennec/string/cstring.h
include/fennec/string/string.h
include/fennec/string/string_view.h
include/fennec/string/detail/_ctype.h
@@ -314,7 +316,9 @@ add_subdirectory(test)
add_library(fennec STATIC
${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)

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 |
| 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 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. |

View File

@@ -18,11 +18,22 @@
# this script handles functionality related to the build process and its info
# Acquire the build name
string(TOLOWER ${CMAKE_BUILD_TYPE} 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")
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()
list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_RELEASE=true)
fennec_add_definitions(FENNEC_RELEASE=true FENNEC_DEBUG=false)
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
# Send a message letting us know the compiler and its version
message(STATUS "Compiler: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}")
# Add definitions for the compiler
fennec_add_definitions(
FENNEC_LONG_COMPILER_NAME="${CMAKE_CXX_COMPILER_ID} ${CMAKE_SYSTEM_NAME} ${CMAKE_SYSTEM_PROCESSOR}"
)
# GCC
if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
set(FENNEC_COMPILER "GCC")
include("${FENNEC_SOURCE_DIR}/cmake/gcc.cmake")
set(FENNEC_COMPILER "GCC")
include("${FENNEC_SOURCE_DIR}/cmake/gcc.cmake")
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
# 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 GCC
fennec_add_definitions(
_GLIBCXX_INCLUDE_NEXT_C_HEADERS=1
FENNEC_COMPILER_GCC=1
FENNEC_GLIBC=1
FENNEC_NO_INLINE=[[gnu::noinline]]
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
)
# Add display and graphics for client builds.
if(FENNEC_USER_CLIENT)
include("${FENNEC_SOURCE_DIR}/cmake/wayland.cmake")
fennec_init_graphics()
fennec_check_wayland()
fennec_init_graphics()
endif()

View File

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

View File

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

View File

@@ -18,12 +18,15 @@
# 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_MINOR 1)
set(FENNEC_VERSION_PATCH 0)
set(FENNEC_VERSION_STRING "${FENNEC_VERSION_MAJOR}.${FENNEC_VERSION_MINOR}.${FENNEC_VERSION_PATCH}")
math(EXPR FENNEC_VERSION_NUM "(${FENNEC_VERSION_MAJOR} << 16) | (${FENNEC_VERSION_MINOR} << 8) | ${FENNEC_VERSION_PATCH}")
# Define the versions for compilation
list(APPEND FENNEC_COMPILE_DEFINITIONS
FENNEC_VERSION_MAJOR=${FENNEC_VERSION_MAJOR}
FENNEC_VERSION_MINOR=${FENNEC_VERSION_MINOR}

View File

@@ -16,24 +16,41 @@
# 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)
find_package(Vulkan COMPONENTS MoltenVK)
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 (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_sources(
include/fennec/renderers/vulkan/lib/app_info.h
include/fennec/renderers/vulkan/lib/instance.h
# Cmake Definition for Vulkan detection
set(FENNEC_FOUND_VULKAN TRUE)
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()
message(WARNING "No Suitable Vulkan implementation found.")

View File

@@ -70,11 +70,12 @@ macro(fennec_check_wayland)
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)
AND (WAYLAND_EGL_INCLUDE_DIR AND WAYLAND_EGL_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_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)
@@ -117,7 +118,7 @@ macro(fennec_check_wayland)
include/fennec/platform/linux/wayland/lib/loader.h source/platform/linux/wayland/lib/loader.cpp
# Fennec Files
include/fennec/platform/linux/wayland/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/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
)
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_HAS_WAYLAND=1
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
# @} 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
# only. Doxygen will then generate output that is more tailored for C. For

View File

@@ -45,19 +45,18 @@ namespace fennec
///
/// \details
/// | Property | Value |
/// |:-----------:|:----------:|
/// |:-----------:|:-----------:|
/// | stable | ✅ |
/// | dynamic | ⛔ |
/// | homogeneous | ✅ |
/// | distinct | ⛔ |
/// | ordered | ⛔ |
/// | space | \f$O(N)\f$ |
/// | linear | ✅ |
/// | access | \f$O(1)\f$ |
/// | find | \f$O(N)\f$ |
/// | space | \emph{O(N)} |
/// | access | \emph{O(1)} |
/// | find | \emph{O(N)} |
/// | insertion | ⛔ |
/// | deletion | ⛔ |
/// | space | \f$O(N)\f$ |
///
/// \tparam ValueT value type
/// \tparam N number of elements
@@ -70,7 +69,7 @@ public:
/// \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.
/// \returns \f$N\f$
/// \returns \emph{N}
///
/// \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
/// \returns \f$ElemV == 0\f$
/// \brief Returns \emph{true} when the array is empty
/// \returns \math{\textbf{ElemV} == 0}
///
/// \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
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr value_t& operator[](size_t i) {
assertd(i < N, "Array Out of Bounds");
@@ -142,7 +141,7 @@ public:
/// \return reference to the requested element
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr const value_t& operator[](size_t i) const {
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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr value_t& front() {
return data[0];
@@ -161,20 +160,20 @@ public:
///
/// \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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr const value_t& front() const {
return data[0];
}
///
/// \returns A reference to \f$data[N - 1]\f$
/// \returns A reference to \math{\textbf{data}[\textbf{N} - 1]}
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr value_t& back() {
return data[N - 1];
@@ -182,10 +181,10 @@ public:
///
/// \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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr const value_t& back() const {
return data[N - 1];
@@ -205,7 +204,7 @@ public:
/// \brief Checks if all elements in the arrays are equal
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
friend constexpr bool_t operator==(const array& lhs, const array& rhs) {
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
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
friend constexpr bool_t operator!=(const array& lhs, const array& rhs) {
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
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr value_t* begin() {
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
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr const value_t* begin() const {
return data;
@@ -255,18 +254,18 @@ public:
/// \returns A pointer to one after the end of the array
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr value_t* end() {
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
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr const value_t* end() const {
return data + N;

View File

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

View File

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

View File

@@ -43,19 +43,18 @@
/// \section fennec_containers_container_section_properties Container Properties
///
/// | Property | Meaning |
/// |:----------------|:-----------------------------------------------------------------------------------------------|
/// |:----------------|:-------------------------------------------------------------------------------------------------------------------|
/// | **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. |
/// | **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. |
/// | **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. |
/// | **linear** | Each element is sequential in terms of access. |
/// | **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. |
/// | **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. |
/// | **space** | The space complexity of the container. |
///
///
/// \section fennec_containers_section_cppstdlib C++ Standard Template Library

View File

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

View File

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

View File

@@ -31,10 +31,13 @@
#ifndef FENNEC_CONTAINERS_DYNARRAY_H
#define FENNEC_CONTAINERS_DYNARRAY_H
#include <fennec/containers/initializer_list.h>
#include <fennec/lang/utility.h>
#include <fennec/memory/allocator.h>
#include <fennec/memory/new.h>
#include <fennec/containers/initializer_list.h>
#include <fennec/format/formatter.h>
namespace fennec
{
@@ -44,19 +47,18 @@ namespace fennec
/// \brief Wrapper for dynamically sized and allocated arrays
/// \details
/// | Property | Value |
/// |:-----------:|:----------:|
/// |:-----------:|:-----------:|
/// | stable | ⛔ |
/// | dynamic | ✅ |
/// | homogeneous | ✅ |
/// | distinct | ⛔ |
/// | ordered | ⛔ |
/// | space | \f$O(N)\f$ |
/// | linear | ✅ |
/// | access | \f$O(1)\f$ |
/// | find | \f$O(N)\f$ |
/// | insertion | \f$O(N)\f$ |
/// | deletion | \f$O(N)\f$ |
/// | space | \f$O(N)\f$ |
/// | space | \emph{O(N)} |
/// | access | \emph{O(1)} |
/// | find | \emph{O(N)} |
/// | insertion | \emph{O(N)} |
/// | deletion | \emph{O(N)} |
///
/// This structure prefers shallow moves and deep copies.
///
@@ -86,7 +88,7 @@ public:
/// \brief Default Constructor, initializes an empty allocation.
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr dynarray()
: _alloc(8)
@@ -99,7 +101,7 @@ public:
/// data.
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
explicit constexpr dynarray(const alloc_t& 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.
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
explicit constexpr dynarray(size_t 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.
/// \param n The number of elements
/// \param alloc The allocator object to copy
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr dynarray(size_t n, const alloc_t& 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
/// \param n the number of elements
/// \param val the value to copy
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr dynarray(size_t n, const TypeT& val)
: _alloc(n)
@@ -166,7 +168,7 @@ public:
/// \param args The arguments to create each object with
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
template<typename...ArgsT>
constexpr explicit dynarray(size_t n, ArgsT&&...args)
@@ -183,7 +185,7 @@ public:
/// \param arr The array to copy
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
template<size_t N>
constexpr dynarray(const TypeT (&arr)[N])
@@ -200,7 +202,7 @@ public:
/// \param arr The array to move
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
template<size_t 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 OAlloc The other allocator type
/// \param conv The dynarray to convert
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
template<typename OTypeT, class OAlloc>
constexpr dynarray(const dynarray<OTypeT, OAlloc>& conv)
@@ -236,7 +238,7 @@ public:
/// \param alloc An allocator object to copy
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr dynarray(initializer_list<value_t> l, const alloc_t& alloc = alloc_t())
: _alloc(l.size(), alloc)
@@ -252,7 +254,7 @@ public:
/// \param arr the dynarray to copy
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr dynarray(const dynarray& arr)
: _alloc(arr._size)
@@ -267,7 +269,7 @@ public:
/// \param arr the dynarray to move
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr dynarray(dynarray&& arr) noexcept
: _alloc(fennec::move(arr._alloc))
@@ -279,7 +281,7 @@ public:
/// \brief Default Destructor, destructs all elements and frees the underlying allocation
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr ~dynarray() {
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 ==========================================================================================================
@@ -307,10 +305,10 @@ public:
///
/// \brief Copy Assignment Operator
/// \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
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr dynarray& operator=(const dynarray& arr) {
this->clear();
@@ -324,10 +322,10 @@ public:
///
/// \brief Move Assignment Operator
/// \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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr dynarray& operator=(dynarray&& arr) noexcept {
this->clear();
@@ -341,10 +339,10 @@ public:
/// \brief Array Copy Assignment Operator
/// \tparam N the length of the array
/// \param arr the array to copy
/// \returns A dynarray after having copied each element of \f$arr\f$
/// \returns A dynarray after having copied each element of \emph{arr}
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
template<size_t N>
constexpr dynarray& operator=(const TypeT (&arr)[N]) {
@@ -360,10 +358,10 @@ public:
/// \brief Array Copy Assignment Operator
/// \tparam N the length of the array
/// \param arr the array to copy
/// \returns A dynarray after having moved each element of \f$arr\f$
/// \returns A dynarray after having moved each element of \emph{arr}
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
template<size_t N>
constexpr dynarray& operator=(TypeT (&&arr)[N]) {
@@ -387,7 +385,7 @@ public:
/// \returns The size of the dynarray in elements
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t size() const {
return _size;
@@ -397,7 +395,7 @@ public:
/// \returns The current capacity, in elements, of the underlying allocation
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t capacity() const {
return _alloc.capacity();
@@ -407,7 +405,7 @@ public:
/// \returns True when there are no elements active, otherwise false
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr bool is_empty() const {
return _size == 0;
@@ -425,10 +423,10 @@ public:
///
/// \brief Array Access Operator
/// \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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr TypeT& operator[](size_t i) {
assertd(i < _size, "Array Out of Bounds");
@@ -438,10 +436,10 @@ public:
///
/// \brief Array Access Operator (const)
/// \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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr const TypeT& operator[](size_t i) const {
assertd(i < _size, "Array Out of Bounds");
@@ -452,7 +450,7 @@ public:
/// \returns Reference to the first element in the dynarray
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr TypeT& front() {
return this->operator[](0);
@@ -462,7 +460,7 @@ public:
/// \returns A const-qualified reference to the first element in the dynarray
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr const TypeT& front() const {
return this->operator[](0);
@@ -472,7 +470,7 @@ public:
/// \returns A reference to the last element in the dynarray
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr TypeT& back() {
return this->operator[](size() - 1);
@@ -482,7 +480,7 @@ public:
/// \returns A const-qualified reference to the last element in the dynarray
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr const TypeT& back() const {
return this->operator[](size() - 1);
@@ -492,7 +490,7 @@ public:
/// \returns A pointer to the underlying allocation
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr TypeT* data() {
return _alloc.data();
@@ -502,7 +500,7 @@ public:
/// \returns A pointer to the underlying allocation
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr const TypeT* data() const {
return _alloc.data();
@@ -523,7 +521,7 @@ public:
/// \param val the value to initialize with
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
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
if((i = min(i, _size)) < _size) {
fennec::memmove(
(void*)(_alloc.data() + i + 1)
, (void*)(_alloc.data() + i)
static_cast<void*>(_alloc.data() + i + 1)
, static_cast<void*>(_alloc.data() + i)
, (_size - i) * sizeof(TypeT));
}
@@ -551,7 +549,7 @@ public:
/// \param val the value to initialize with
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
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
if((i = min(i, _size)) < _size) {
fennec::memmove(
(void*)(_alloc.data() + i),
(void*)(_alloc.data() + i + 1),
static_cast<void*>(_alloc.data() + i),
static_cast<void*>(_alloc.data() + i + 1),
(_size - i) * sizeof(TypeT)
);
}
@@ -581,7 +579,7 @@ public:
/// \tparam ArgsT Argument types
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
template<typename...ArgsT>
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
if((i = min(i, _size)) < _size) {
fennec::memmove(
(void*)(_alloc.data() + i)
, (void*)(_alloc.data() + i + 1)
static_cast<void*>(_alloc.data() + i)
, static_cast<void*>(_alloc.data() + i + 1)
, (_size - i) * sizeof(TypeT));
}
@@ -609,7 +607,7 @@ public:
/// \param val Value to initialize with
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr void push_back(const TypeT& val) {
dynarray::insert(_size, val);
@@ -620,7 +618,7 @@ public:
/// \param val Value to initialize with
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr void push_back(TypeT&& val) {
dynarray::insert(_size, fennec::forward<TypeT>(val));
@@ -632,7 +630,7 @@ public:
/// \param args Arguments to construct with
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
template<typename...ArgsT>
constexpr void emplace_back(ArgsT...args) {
@@ -643,7 +641,7 @@ public:
/// \brief Erase last element
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr void pop_back() {
fennec::destruct(&_alloc[--_size]);
@@ -653,10 +651,10 @@ public:
/// \brief Resize the dynarray, invoking the default constructor for all new 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
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr void resize(size_t n) {
_reduce(n);
@@ -674,10 +672,10 @@ public:
/// \param n The new size in elements
/// \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
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr void resize(size_t n, const TypeT& val) {
_reduce(n);
@@ -694,10 +692,10 @@ public:
/// \brief Reserve the array, allocating new space without initialization
/// \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
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr void reserve(size_t n) {
_reduce(n);
@@ -708,7 +706,7 @@ public:
/// \brief Clears the contents of the dynarray, destructing all elements and releasing the allocation.
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr void clear() {
_reduce(0);
@@ -728,16 +726,16 @@ public:
/// \returns A pointer to the first element in the dynarray
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
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
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
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
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
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
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
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

View File

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

View File

@@ -35,7 +35,6 @@
#include <fennec/containers/list.h>
#include <fennec/containers/map.h>
#include <fennec/containers/object_pool.h>
#include <fennec/containers/set.h>
/*
* With the directed tree we were able to cheat a little, the structure has more rules to it which allows
@@ -56,19 +55,18 @@ namespace fennec
///
/// \details
/// | Property | Value |
/// |:-----------:|:--------------:|
/// |:-----------:|:---------------:|
/// | stable | ⛔ |
/// | dynamic | ✅ |
/// | homogeneous | ✅ |
/// | distinct | ⛔ |
/// | ordered | ⛔ |
/// | space | \f$O(N)\f$ |
/// | linear | ✅ |
/// | access | \f$O(1)\f$ |
/// | find | \f$O(1)\f$ |
/// | insertion | \f$O(1)\f$ |
/// | deletion | \f$O(M)\f$ |
/// | space | \f$O(N + M)\f$ |
/// | space | \emph{O(N + M)} |
/// | access | \emph{O(1)} |
/// | find | \emph{O(1)} |
/// | insertion | \emph{O(1)} |
/// | deletion | \emph{O(M)} |
///
/// Graphs contain vertices and edges. Graphs are either directed
/// 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
/// 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
/// pair of vertices \f$[u, v]\f$. We will call this "unilateral"
/// 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 \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
/// of vertices \f$[u, v]\f$. We will call this "connected"
/// 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 \emph{[u, v]}. We will call this "connected"
///
/// \tparam VertexT The type associated with each vertex
/// \tparam EdgeT The type associated with each edge
@@ -122,7 +120,7 @@ public:
/// \brief Default Constructor, initializes empty graph
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr graph() = default;
@@ -130,7 +128,7 @@ public:
/// \brief Destructor
///
/// \par Complexity
/// \f$O(N + M)\f$
/// \math{\textbf{O(N} + \textbf{M)}}
///
constexpr ~graph() = default;
@@ -146,7 +144,7 @@ public:
/// \returns A reference to this after assigning g
///
/// \par Complexity
/// \f$O(N + M)\f$
/// \math{\textbf{O(N} + \textbf{M)}}
///
constexpr graph& operator=(const graph& g) = default;
@@ -156,7 +154,7 @@ public:
/// \returns A reference to this after assigning g
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr graph& operator=(graph&& g) = default;
@@ -172,7 +170,7 @@ public:
/// \returns The number of vertices in the graph
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t num_vertices() const {
return _vertex_pool.size();
@@ -182,7 +180,7 @@ public:
/// \returns The number of edges in the graph
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t num_edges() const {
return _edge_pool.size();
@@ -192,57 +190,57 @@ public:
/// \returns The capacity of the vertex pool
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t capacity() const {
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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr bool is_empty() const {
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 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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr bool exists(size_t a, size_t b) const {
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$
/// and ends at \f$a\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 \emph{a}
/// \param a The first 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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr bool is_symmetric(size_t a, size_t b) const {
return exists(a, b) and exists(b, a);
}
///
/// \brief Checks if there exists an edge \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 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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr bool is_undirected(size_t a, size_t b) const {
const auto* e0 = _edge_map[a][b];
@@ -269,7 +267,7 @@ public:
/// \returns A reference to the value stored in the vertex
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr vertex_t& operator[](size_t vertex) {
return _vertex_pool[vertex];
@@ -281,7 +279,7 @@ public:
/// \returns A reference to the value stored in the vertex
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr const vertex_t& operator[](size_t vertex) const {
return _vertex_pool[vertex];
@@ -291,10 +289,10 @@ public:
/// \brief edge Access Operator
/// \param a The id of the first vertex
/// \param b The id of the second vertex
/// \returns A pointer to the value stored in the edge, \f$nullptr\f$ if not found
/// \returns A pointer to the value stored in the edge, \emph{nullptr} if not found
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr edge_t* operator[](size_t a, size_t b) {
if (is_empty()) {
@@ -311,10 +309,10 @@ public:
/// \brief edge Const Access Operator
/// \param a The id of the first vertex
/// \param b The id of the second vertex
/// \returns A const-qualified pointer to the value stored in the edge, \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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr const edge_t* operator[](size_t a, size_t b) const {
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
/// \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
/// \f$O(M)\f$
/// \emph{O(M)}
///
list<size_t> outgoing(size_t vertex) {
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
/// \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
/// \f$O(M)\f$
/// \emph{O(M)}
///
list<size_t> incoming(size_t vertex) {
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
/// \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
/// \f$O(M)\f$
/// \emph{O(M)}
///
list<size_t> symmetric(size_t vertex) {
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
/// "Joined" edges may also be referred to as "undirected." A joined, or undirected, edge may be
/// turned into a directed edge by changing the weight object associated with the edge, or by
/// removing one of the sub-edges.
/// \param vertex The id of the vertex
/// \returns A list containing all vertices \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
/// \f$O(M)\f$
/// \emph{O(M)}
///
list<size_t> undirected(size_t vertex) {
list<size_t> res;
@@ -421,7 +419,7 @@ public:
/// \returns A pointer to a map containing edges mapped from this vertex
///
/// \par Complexity
/// \f$O(M)\f$
/// \emph{O(M)}
///
const auto* edges(size_t vertex) {
if (is_empty() || vertex >= _edge_map.size()) {
@@ -444,7 +442,7 @@ public:
/// \returns The id of the new vertex
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t insert(vertex_t&& vertex) {
return this->_insert(fennec::forward<vertex_t>(vertex));
@@ -456,7 +454,7 @@ public:
/// \returns The id of the new vertex
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t insert(const vertex_t& vertex) {
return this->_insert(vertex);
@@ -469,7 +467,7 @@ public:
/// \returns The id of the new vertex
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
template<typename...ArgsT>
constexpr size_t emplace(ArgsT&&...args) {
@@ -481,7 +479,7 @@ public:
/// \param vertex The id of the vertex to erase
///
/// \par Complexity
/// \f$O(M)\f$
/// \emph{O(M)}
///
constexpr void erase(size_t 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
/// \param a The first vertex id
/// \param b The second vertex id
/// \param args The arguments to construct the edge with
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
template<typename...ArgsT>
constexpr void make_edge(size_t a, size_t b, ArgsT&&...args) {
@@ -508,7 +506,7 @@ public:
_edge_map.resize(_vertex_pool.capacity());
}
auto it = _edge_map[a][b];
const auto it = _edge_map[a][b];
size_t conn;
if (it != nullptr) {
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
/// \param a The first vertex id
/// \param b The second vertex id
/// \param args The arguments to construct the edge with
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
template<typename...ArgsT>
constexpr void make_edge2(size_t a, size_t b, ArgsT&&...args) {
@@ -539,7 +537,7 @@ public:
_edge_map.resize(_vertex_pool.capacity());
}
auto it = _edge_map[a][b];
const auto it = _edge_map[a][b];
size_t conn;
if (it != nullptr) {
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 b The second vertex id
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
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 b The second vertex id
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr void cut_edge2(size_t a, size_t 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
///
/// \par Complexity
/// \f$O(M)\f$
/// \emph{O(M)}
///
void cut(size_t n) {
for (const auto it : outgoing(n)) {
@@ -619,7 +617,7 @@ public:
/// \brief Clear the graph, destructing all vertices and edges.
///
/// \par Complexity
/// \f$O(N + M)\f$
/// \emph{O(N + M)}
///
void clear() {
_vertex_pool.clear();

View File

@@ -44,7 +44,7 @@ using std::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>
constexpr const T* begin(initializer_list<T> inls) noexcept {
return inls.begin();
@@ -52,7 +52,7 @@ constexpr const T* begin(initializer_list<T> inls) noexcept {
///
/// \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>
constexpr const T* end(initializer_list<T> inls) noexcept {
return inls.end();

View File

@@ -49,22 +49,21 @@ namespace fennec
/// following properties:
///
/// | Property | Value |
/// |:-----------:|:----------:|
/// |:-----------:|:-----------:|
/// | stable | ⛔ |
/// | dynamic | ✅ |
/// | homogeneous | ✅ |
/// | distinct | ⛔ |
/// | ordered | ⛔ |
/// | space | \f$O(N)\f$ |
/// | linear | ✅ |
/// | access | \f$O(N)\f$ |
/// | find | \f$O(N)\f$ |
/// | insertion | \f$O(N)\f$ |
/// | deletion | \f$O(N)\f$ |
/// | space | \f$O(N)\f$ |
/// | space | \emph{O(N)} |
/// | access | \emph{O(N)} |
/// | find | \emph{O(N)} |
/// | insertion | \emph{O(N)} |
/// | deletion | \emph{O(N)} |
///
/// \note Access, Insertion, and Deletion are \f$O(N)\f$ using the index pattern,
/// using the iterator pattern yields \f$O(1)\f$ runtime.
/// \note Access, Insertion, and Deletion are \emph{O(N)} using the index pattern,
/// using the iterator pattern yields \emph{O(1)} runtime.
///
/// \tparam TypeT value type
template<class TypeT, class Alloc = allocator<TypeT>>
@@ -106,18 +105,18 @@ public:
/// \brief Default Constructor, initializes an empty list.
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr list()
: _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
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr list(const list& l)
: list() {
@@ -132,7 +131,7 @@ public:
/// \param l The list to move
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr list(list&& l) noexcept
: _table(fennec::move(l._table))
@@ -146,7 +145,7 @@ public:
/// \brief Destructor, destructs all elements then releases the allocation.
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr ~list() {
clear();
@@ -163,10 +162,10 @@ public:
///
/// \brief Copy Assignment Operator
/// \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
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr list& operator=(const list& l) {
this->clear();
@@ -179,10 +178,10 @@ public:
///
/// \brief Move Assignment Operator
/// \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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr list& operator=(list&& l) noexcept {
this->clear();
@@ -206,7 +205,7 @@ public:
/// \returns The size of the list in elements.
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t size() const {
return _size;
@@ -216,17 +215,17 @@ public:
/// \returns The capacity of the list in elements.
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t capacity() const {
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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr bool is_empty() const {
return _root == npos;
@@ -244,10 +243,10 @@ public:
///
/// \brief Array Access Operator
/// \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
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr value_t& operator[](int i) {
assertd(i >= 0 && size_t(i) < _size, "Index out of Bounds");
@@ -259,10 +258,10 @@ public:
///
/// \brief Const Array Access Operator
/// \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
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr const value_t& operator[](int i) const {
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
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr value_t& front() {
return *_table[_root].value;
@@ -287,7 +286,7 @@ public:
/// \returns A const-qualified reference to the first element in the list
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr const value_t& front() const {
return *_table[_root].value;
@@ -298,7 +297,7 @@ public:
/// \returns A reference to the last element in the list
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr value_t& back() {
return *_table[_last].value;
@@ -309,7 +308,7 @@ public:
/// \returns A const-qualified reference to the last element in the list
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr const value_t& back() const {
return *_table[_last].value;
@@ -331,7 +330,7 @@ public:
/// \returns The id of the inserted node
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr iterator insert(const iterator& it, const value_t& x) {
return this->_insert(it._n, x);
@@ -344,7 +343,7 @@ public:
/// \returns The id of the inserted node
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr iterator insert(const iterator& it, 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
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr iterator insert(size_t i, const value_t& x) {
assert(i <= size(), "Index out of Bounds");
@@ -373,7 +372,7 @@ public:
/// \returns The id of the inserted node
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr iterator insert(size_t i, value_t&& x) {
assert(i <= size(), "Index out of Bounds");
@@ -390,7 +389,7 @@ public:
/// \returns The id of the inserted node
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
template<typename...ArgsT>
constexpr iterator emplace(size_t i, ArgsT&&...args) {
@@ -408,7 +407,7 @@ public:
/// \returns The id of the inserted node
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
template<typename...ArgsT>
constexpr iterator emplace(const iterator& it, ArgsT&&...args) {
@@ -421,7 +420,7 @@ public:
/// \returns The id of the inserted node
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr iterator push_front(const value_t& x) {
return this->_insert(_root, x);
@@ -433,7 +432,7 @@ public:
/// \returns The id of the inserted node
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr iterator push_front(value_t&& x) {
return this->_insert(_root, fennec::forward<value_t>(x));
@@ -446,7 +445,7 @@ public:
/// \returns The id of the inserted node
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
template<typename...ArgsT>
constexpr iterator emplace_front(ArgsT&&...args) {
@@ -459,7 +458,7 @@ public:
/// \returns The id of the inserted node
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr iterator push_back(const value_t& x) {
return this->_insert(npos, x);
@@ -471,7 +470,7 @@ public:
/// \returns The id of the inserted node
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr iterator push_back(value_t&& x) {
return this->_insert(npos, fennec::forward<value_t>(x));
@@ -484,7 +483,7 @@ public:
/// \returns The id of the inserted node
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
template<typename...ArgsT>
constexpr iterator emplace_back(ArgsT&&...args) {
@@ -496,11 +495,11 @@ public:
/// \param i Index to erase
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr void erase(size_t i) {
assert(i < size(), "Index out of Bounds!");
size_t n = _walk(i);
const size_t n = _walk(i);
_erase(n);
}
@@ -509,7 +508,7 @@ public:
/// \param it Location to Erase
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr void erase(const iterator& it) {
this->_erase(it._n);
@@ -519,7 +518,7 @@ public:
/// \brief Pop Front, erases first element
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr void pop_front() {
_erase(_root);
@@ -529,7 +528,7 @@ public:
/// \brief Pop Back, erases first element
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr void pop_back() {
_erase(_last);
@@ -539,7 +538,7 @@ public:
/// \brief Clears the list, destructing all elements in order
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr void clear() {
size_t i = _root;
@@ -564,18 +563,18 @@ public:
/// \returns An iterator for the first element in the list
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr iterator begin() {
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
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr const_iterator begin() const {
return const_iterator(this, _root);
@@ -585,25 +584,25 @@ public:
/// \returns An iterator for the end of the list
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr iterator end() {
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
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr const_iterator end() const {
return const_iterator(this, npos);
}
///
/// \brief C++ Iterator Specification \f$iterator\f$
/// \brief C++ Iterator Specification \emph{iterator}
class iterator {
public:
///
@@ -615,7 +614,7 @@ public:
///
/// \brief prefix increment operator
/// \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) {
rhs._n = rhs._list->_next(rhs._n);
return rhs;
@@ -624,7 +623,7 @@ public:
///
/// \brief postfix increment operator
/// \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) {
iterator prev = lhs;
++lhs;
@@ -648,7 +647,7 @@ public:
///
/// \brief iterator equality operator
/// \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) {
return _list == it._list and _n == it._n;
}
@@ -656,7 +655,7 @@ public:
///
/// \brief iterator inequality operator
/// \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) {
return _list != it._list or _n != it._n;
}
@@ -685,7 +684,7 @@ public:
///
/// \brief prefix increment operator
/// \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) {
if (rhs._list->_next(rhs._n) < rhs._list->capacity()) {
return rhs;
@@ -697,7 +696,7 @@ public:
///
/// \brief postfix increment operator
/// \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) {
const_iterator prev = lhs;
++lhs;
@@ -721,7 +720,7 @@ public:
///
/// \brief iterator equality operator
/// \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) {
return _list == it._list and _n == it._n;
}
@@ -729,7 +728,7 @@ public:
///
/// \brief iterator inequality operator
/// \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) {
return _list != it._list or _n != it._n;
}
@@ -800,7 +799,7 @@ private:
constexpr size_t _next_free() {
if (not _freed.is_empty()) {
size_t n = _freed.back();
const size_t n = _freed.back();
_freed.pop_back();
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
/// | Property | Value |
/// |:-----------:|:----------:|
/// |:-----------:|:-----------:|
/// | stable | ⛔ |
/// | dynamic | ✅ |
/// | homogeneous | ✅ |
/// | distinct | ✅ |
/// | ordered | ⛔ |
/// | space | \f$O(N)\f$ |
/// | linear | ⛔ |
/// | access | \f$O(1)\f$ |
/// | find | \f$O(1)\f$ |
/// | insertion | \f$O(1)\f$ |
/// | deletion | \f$O(1)\f$ |
/// | space | \f$O(N)\f$ |
/// | space | \emph{O(N)} |
/// | access | \emph{O(1)} |
/// | find | \emph{O(1)} |
/// | insertion | \emph{O(1)} |
/// | deletion | \emph{O(1)} |
///
/// \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 ValueT The Value Type
@@ -102,7 +101,7 @@ public:
/// \brief key hash helper
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
/// \returns the hash of the key
constexpr size_t operator()(const elem_t& p) const {
@@ -114,10 +113,10 @@ public:
/// \brief key comparison helper
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 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 {
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 {
return _set.size();
}
@@ -179,10 +178,10 @@ public:
///
/// \brief Key Access Operator
/// \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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr value_t* operator[](const KeyT& key) {
auto it = _set.at(this->_find(key));
@@ -192,10 +191,10 @@ public:
///
/// \brief Key Const Access Operator
/// \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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr const value_t* operator[](const KeyT& key) const {
auto it = _set.at(this->_find(key));
@@ -206,10 +205,10 @@ public:
/// \brief Argument Key Access Operator
/// \tparam ArgsT Argument Types
/// \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
/// \f$O(1)\f$
/// \emph{O(1)}
///
template<typename...ArgsT>
constexpr value_t* operator[](ArgsT&&...args) {
@@ -221,10 +220,10 @@ public:
/// \brief Argument Key Const Access Operator
/// \tparam ArgsT Argument Type
/// \param args Argument to construct the key with
/// \returns A const-qualified pointer to the value associated with \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
/// \f$O(1)\f$
/// \emph{O(1)}
///
template<typename...ArgsT>
constexpr const value_t* operator[](ArgsT&&...args) const {
@@ -246,7 +245,7 @@ public:
/// \param pair a pair containing the key and its value
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr void insert(elem_t&& pair) {
this->_insert(fennec::forward<elem_t>(pair));
@@ -258,7 +257,7 @@ public:
/// \param args Arguments for constructing the key-value pair
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
template<typename...ArgsT>
constexpr void emplace(const KeyT& key, ArgsT&&...args) {
@@ -270,7 +269,7 @@ public:
/// \param args Arguments for constructing the key-value pair
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
template<typename...ArgsT>
constexpr void emplace(ArgsT&&...args) {
@@ -282,7 +281,7 @@ public:
/// \param key key to erase
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr void erase(KeyT&& key) {
_set.erase(this->_find(fennec::forward<KeyT>(key)));
@@ -293,7 +292,7 @@ public:
/// \param key key to erase
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr void erase(const KeyT& key) {
_set.erase(this->_find(key));
@@ -305,7 +304,7 @@ public:
/// \param args Arguments to construct a key to erase
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
template<typename...ArgsT>
constexpr void erase(ArgsT&&...args) {
@@ -316,7 +315,7 @@ public:
/// \brief Clears the map destructing all elements
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
void 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
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr iterator 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
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr iterator end() {
return _set.end();

View File

@@ -42,19 +42,18 @@ namespace fennec
/// \brief Struct which holds a pool of objects associated with ids
/// \details
/// | Property | Value |
/// |:-----------:|:----------:|
/// |:-----------:|:-----------:|
/// | stable | ⛔ |
/// | dynamic | ✅ |
/// | homogeneous | ✅ |
/// | distinct | ⛔ |
/// | ordered | ⛔ |
/// | space | \f$O(N)\f$ |
/// | linear | ⛔ |
/// | access | \f$O(1)\f$ |
/// | find | \f$O(N)\f$ |
/// | insertion | \f$O(1)\f$ |
/// | deletion | \f$O(1)\f$ |
/// | space | \f$O(N)\f$ |
/// | space | \emph{O(N)} |
/// | access | \emph{O(1)} |
/// | find | \emph{O(N)} |
/// | insertion | \emph{O(1)} |
/// | deletion | \emph{O(1)} |
///
/// \tparam TypeT The value type
/// \tparam AllocT The allocator type
@@ -88,7 +87,7 @@ public:
/// \brief Default Constructor, initializes an empty object pool
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr object_pool()
: _size(0) {
@@ -98,7 +97,7 @@ public:
/// \brief Default Destructor, destructs objects then releases the allocation.
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr ~object_pool() = default;
@@ -114,7 +113,7 @@ public:
/// \returns The number of active objects in the pool
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t size() const {
return _size;
@@ -124,30 +123,30 @@ public:
/// \returns The capacity of the underlying allocation
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t capacity() const {
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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr bool is_empty() const {
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.
/// \returns The id of the next inserted node
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t next_id() const {
size_t next = _size;
@@ -167,10 +166,10 @@ public:
///
/// \brief Array Access Operator
/// \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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr value_t& operator[](size_t i) {
assert(i < capacity(), "Index out of Bounds!");
@@ -181,10 +180,10 @@ public:
///
/// \brief Array Const Access Operator
/// \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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr const value_t& operator[](size_t i) const {
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
/// \returns An integer corresponding to the id of the node
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t insert(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
/// \returns An integer corresponding to the id of the node
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t insert(const value_t& 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
/// \returns An integer corresponding to the id of the node
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
template<typename...ArgsT>
constexpr size_t emplace(ArgsT&&...args) {
@@ -248,7 +247,7 @@ public:
/// \param i The id of the object
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr void erase(size_t i) {
_table[i] = nullopt;
@@ -260,7 +259,7 @@ public:
/// \brief Clear the object pool
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr void clear() {
_table.clear();
@@ -277,18 +276,18 @@ public:
/// \returns an iterator at the start of the object pool
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
iterator begin() {
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
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
const_iterator begin() const {
return const_iterator(this, 0);
@@ -298,25 +297,25 @@ public:
/// \returns an iterator at the start of the end of the object pool
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
iterator end() {
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
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
const_iterator end() const {
return const_iterator(this, _size);
}
///
/// \brief C++ Iterator Specification \f$iterator\f$
/// \brief C++ Iterator Specification \emph{iterator}
class iterator {
public:
///
@@ -337,18 +336,18 @@ public:
///
/// \brief copy assignment
/// \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;
///
/// \brief move assignment
/// \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;
///
/// \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) {
iterator ret = it;
++it.curr;
@@ -358,7 +357,7 @@ public:
///
/// \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) {
++it.curr;
it._fix();
@@ -382,7 +381,7 @@ public:
///
/// \brief iterator equality operator
/// \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) {
return pool == it.pool and curr == it.curr;
}
@@ -390,7 +389,7 @@ public:
///
/// \brief iterator inequality operator
/// \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) {
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 {
public:
///
@@ -435,18 +434,18 @@ public:
///
/// \brief copy assignment
/// \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;
///
/// \brief move assignment
/// \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;
///
/// \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) {
const_iterator ret = it;
++it.curr;
@@ -456,7 +455,7 @@ public:
///
/// \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) {
++it.curr;
it._fix();
@@ -480,7 +479,7 @@ public:
///
/// \brief iterator equality operator
/// \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) {
return pool == it.pool and curr == it.curr;
}
@@ -488,7 +487,7 @@ public:
///
/// \brief iterator inequality operator
/// \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) {
return pool != it.pool or curr != it.curr;
}

View File

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

View File

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

View File

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

View File

@@ -32,7 +32,7 @@
#define FENNEC_CONTAINERS_RDTREE_H
#include <fennec/containers/list.h>
#include <fennec/containers/optional.h>
#include <fennec/containers/deque.h>
#include <fennec/containers/traversal.h>
#include <fennec/containers/pair.h>
@@ -45,19 +45,18 @@ namespace fennec
/// \brief Rooted-Directed Tree
/// \details
/// | Property | Value |
/// |:-----------:|:----------:|
/// |:-----------:|:-----------:|
/// | stable | ⛔ |
/// | dynamic | ✅ |
/// | homogeneous | ✅ |
/// | distinct | ⛔ |
/// | ordered | ⛔ |
/// | space | \f$O(N)\f$ |
/// | linear | ⛔ |
/// | access | \f$O(1)\f$ |
/// | find | \f$O(N)\f$ |
/// | insertion | \f$O(1)\f$ |
/// | deletion | \f$O(1)\f$ |
/// | space | \f$O(N)\f$ |
/// | space | \emph{O(N)} |
/// | access | \emph{O(1)} |
/// | find | \emph{O(N)} |
/// | insertion | \emph{O(1)} |
/// | deletion | \emph{O(1)} |
///
/// \tparam TypeT Data type
/// \tparam AllocT Allocator Type
@@ -133,7 +132,7 @@ public:
/// \param args The arguments to construct the root with
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
template<typename...ArgsT>
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
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr rdtree(const rdtree& tree)
: _table(tree._table), _freed(tree._freed), _size(tree._size) {
// TODO: properly invoke copy constructor for all elements
constexpr rdtree(const rdtree& tree) {
_table.reallocate(tree.size());
// 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
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr rdtree(rdtree&& tree) noexcept
: _table(fennec::move(tree._table)), _freed(fennec::move(tree._freed)), _size(tree._size) {
@@ -176,10 +214,10 @@ public:
///
/// \brief Copy Assignment Operator
/// \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
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr rdtree& operator=(const rdtree& rhs) {
// TODO: properly invoke copy constructor for all elements
@@ -195,10 +233,10 @@ public:
///
/// \brief Move Assignment Operator
/// \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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr rdtree& operator=(rdtree&& rhs) noexcept {
for (value_t* it : _table) {
@@ -221,7 +259,7 @@ public:
/// \returns The number of nodes in the tree
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t size() const {
return _size;
@@ -231,17 +269,17 @@ public:
/// \returns The capacity of the underlying allocation
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t capacity() const {
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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr bool is_empty() const {
return _size == 0;
@@ -260,7 +298,7 @@ public:
/// \returns The id of the parent node
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t parent(size_t i) const {
if (i >= _table.capacity()) return npos;
@@ -273,11 +311,11 @@ public:
/// \returns The id of the child node
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t child(size_t i, size_t n = 0) const {
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)
return next(c, n == npos ? npos : n - 1);
return c;
@@ -289,7 +327,7 @@ public:
/// \returns The id of the next node
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t next(size_t i, size_t n = 0) const {
if (i >= _table.capacity() && n != npos) return npos;
@@ -297,7 +335,7 @@ public:
return npos;
}
size_t org = i;
const size_t org = i;
size_t nxt = _table[i].next;
while (nxt != npos) {
i = nxt;
@@ -318,7 +356,7 @@ public:
/// \returns The id of the previous node
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t prev(size_t i, size_t n = 0) const {
if (i >= _table.capacity()) return npos;
@@ -326,7 +364,7 @@ public:
return npos;
}
size_t org = i;
const size_t org = i;
size_t prv = _table[i].prev;
while (prv != npos) {
i = prv;
@@ -343,10 +381,10 @@ public:
///
/// \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
/// \f$O(\log N)\f$
/// \emph{O(\log N)}
///
constexpr size_t left_most(size_t i) const {
if (i >= _table.capacity()) return npos;
@@ -355,7 +393,7 @@ public:
return i;
}
while (true) {
size_t p = n;
const size_t p = n;
if ((n = child(n)) == npos) {
return p;
}
@@ -364,10 +402,10 @@ public:
///
/// \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
/// \f$O(\log N)\f$
/// \emph{O(\log N)}
///
constexpr size_t right_most(size_t i) const {
if (i >= _table.capacity()) return npos;
@@ -391,7 +429,7 @@ public:
/// \returns The depth of the node
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t depth(size_t i) const {
if (i >= _table.capacity()) return npos;
@@ -403,7 +441,7 @@ public:
/// \returns The number of children the node has
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t num_children(size_t i) const {
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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t next_id() const {
size_t i = _size;
@@ -429,7 +467,7 @@ public:
/// \returns A reference to the value of the node wrapped in an optional
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr value_t& operator[](size_t i) {
return _table[i].value;
@@ -440,7 +478,7 @@ public:
/// \returns A const-qualified reference to the value of the node wrapped in an optional
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr const value_t& operator[](size_t i) const {
return _table[i].value;
@@ -455,28 +493,28 @@ public:
/// @{
///
/// \brief Insertion, creates a node in the tree with parent \f$parent\f$
/// \param parent the parent node, if \f$npos\f$ sets the value of the root node
/// \brief Insertion, creates a node in the tree with parent \emph{parent}
/// \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 val the value to insert
/// \returns the index of the created node
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t insert(size_t parent, size_t next, const value_t& val) {
return this->_insert(parent, next, val);
}
///
/// \brief Insertion, creates a node in the tree with parent \f$parent\f$
/// \param parent the parent node, if \f$npos\f$ sets the value of the root node
/// \brief Insertion, creates a node in the tree with parent \emph{parent}
/// \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 val the value to insert
/// \returns the index of the created node
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t insert(size_t parent, size_t next, 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
/// \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 tree the tree to insert
/// \returns the index of the inserted root
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t insert(size_t parent, size_t next, const rdtree& tree) {
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$
/// \param parent the parent node, if \f$npos\f$ sets the value of the root node
/// \brief Insertion, creates a node in the tree with parent \emph{parent}
/// \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 args the args to construct the value to insert
/// \returns the index of the created node
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
template<typename...ArgsT>
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
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr void swap(size_t i0, size_t i1) {
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
///
/// \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
///
/// \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 i The node to start at
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
template<typename OrderT, typename VisitorT>
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
///
/// \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
///
/// \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 i The node to start at
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
template<typename OrderT, typename VisitorT>
constexpr void traverse(VisitorT&& visit, size_t i = root) const {
@@ -657,8 +695,8 @@ public:
return npos;
}
size_t nxt = tree.next(node);
size_t chd = tree.next(node);
const size_t nxt = tree.next(node);
const size_t chd = tree.next(node);
if (nxt != npos && node != head) {
visit.push_front(nxt);
@@ -680,7 +718,7 @@ public:
private:
list<size_t> visit;
size_t head;
size_t head = npos;
};
///
@@ -707,8 +745,8 @@ public:
return npos;
}
size_t nxt = tree.next(node);
size_t chd = tree.child(node);
const size_t nxt = tree.next(node);
const size_t chd = tree.child(node);
if (nxt != npos && node != head) {
visit.push_front(nxt);
@@ -730,7 +768,7 @@ public:
private:
list<size_t> visit;
size_t head;
size_t head = npos;
};
///
@@ -757,8 +795,8 @@ public:
return npos;
}
size_t prnt = tree.parent(node);
size_t next = tree.next(node);
const size_t prnt = tree.parent(node);
const size_t next = tree.next(node);
if (node != head) {
if (tree.child(prnt) == node) {
visit.push_back(prnt);
@@ -782,7 +820,7 @@ public:
private:
list<size_t> visit;
size_t head;
size_t head = npos;
};
///
@@ -809,8 +847,8 @@ public:
return npos;
}
size_t prnt = tree.parent(node);
size_t next = tree.next(node);
const size_t prnt = tree.parent(node);
const size_t next = tree.next(node);
if (node != head) {
if (next != npos) {
@@ -832,7 +870,7 @@ public:
private:
list<size_t> visit;
size_t head;
size_t head = npos;
};
/// @}

View File

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

View File

@@ -50,19 +50,18 @@ namespace fennec
/// This data-structure behaves like a set, but does not use pointers, instead storing the table in-array
///
/// | Property | Value |
/// |:-----------:|:----------:|
/// |:-----------:|:-----------:|
/// | stable | ⛔ |
/// | dynamic | ✅ |
/// | homogeneous | ✅ |
/// | distinct | ✅ |
/// | ordered | ⛔ |
/// | space | \f$O(N)\f$ |
/// | linear | ✅ |
/// | access | \f$O(1)\f$ |
/// | find | \f$O(1)\f$ |
/// | insertion | \f$O(1)\f$ |
/// | deletion | \f$O(1)\f$ |
/// | space | \f$O(N)\f$ |
/// | space | \emph{O(N)} |
/// | access | \emph{O(1)} |
/// | find | \emph{O(1)} |
/// | insertion | \emph{O(1)} |
/// | deletion | \emph{O(1)} |
///
/// \tparam TypeT The type to contain
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
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr set()
: _table()
@@ -127,7 +126,7 @@ public:
/// \param hash the hash object
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr set(const hash_t& hash)
: _table()
@@ -142,7 +141,7 @@ public:
/// \param alloc the allocator object
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr set(const alloc_t& alloc)
: _table(alloc)
@@ -158,7 +157,7 @@ public:
/// \param alloc the allocator object
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr set(const hash_t& hash, const alloc_t& alloc)
: _table(alloc)
@@ -173,7 +172,7 @@ public:
/// \param set Set to copy
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr set(const set& set)
: _table(set._table)
@@ -188,7 +187,7 @@ public:
/// \param set Set to move
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr set(set&& set) noexcept
: _table(fennec::move(set._table))
@@ -202,7 +201,7 @@ public:
/// \brief Destructor, destructs all elements and releases the allocation
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr ~set() {
for (size_t i = 0; i < capacity(); ++i) {
@@ -222,17 +221,17 @@ public:
/// \returns Size of the set in elements
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t size() const {
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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr bool is_empty() const {
return _size == 0;
@@ -242,7 +241,7 @@ public:
/// \returns Capacity of the set in elements
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr size_t capacity() const {
return _table.size();
@@ -262,7 +261,7 @@ public:
/// \returns An iterator at the location of the value
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr iterator find(const elem_t& val) const {
if (capacity() == 0) {
@@ -311,10 +310,10 @@ public:
///
/// \brief Check if a set contains a value
/// \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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr bool contains(const elem_t& val) const {
return this->find(val) != end();
@@ -323,11 +322,11 @@ public:
///
/// \brief Iterator 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.
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr elem_t* at(const iterator& it) {
if (it == end()) {
@@ -342,10 +341,10 @@ public:
///
/// \brief Iterator Const 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
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr const elem_t* at(const iterator& it) const {
if (not _table[it._i].value) return nullptr;
@@ -365,7 +364,7 @@ public:
/// \returns An iterator at the held value
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr iterator insert(elem_t&& val) {
return this->_insert(fennec::forward<elem_t>(val));
@@ -377,7 +376,7 @@ public:
/// \returns An iterator at the held value
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr iterator insert(const elem_t& val) {
return this->_insert(val);
@@ -390,7 +389,7 @@ public:
/// \returns An iterator at the held value
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
template<typename...ArgsT>
constexpr iterator emplace(ArgsT&&...args) {
@@ -402,7 +401,7 @@ public:
/// \param it Location to erase
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr void erase(iterator it) {
size_t i = it._i;
@@ -431,7 +430,7 @@ public:
/// \param val Value to erase
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr void erase(const elem_t& val) {
this->erase(this->find(val));
@@ -441,7 +440,7 @@ public:
/// \brief Clear all elements from the set, destructing them
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
constexpr void 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
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr iterator begin() const {
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
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
constexpr iterator end() const {
return iterator(this, npos);
@@ -484,10 +483,10 @@ public:
/// @}
///
/// \brief C++ Iterator Specification \f$iterator\f$
/// \brief C++ Iterator Specification \emph{iterator}
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
class iterator {
public:
@@ -500,7 +499,7 @@ public:
///
/// \brief prefix increment operator
/// \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) {
while (++it._i < it._set->capacity()) {
if (it._set->_table[it._i].value) {
@@ -514,7 +513,7 @@ public:
///
/// \brief postfix increment operator
/// \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) {
iterator prev = it;
++it;
@@ -539,7 +538,7 @@ public:
///
/// \brief iterator equality operator
/// \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 {
return _set == it._set and _i == it._i;
}
@@ -547,7 +546,7 @@ public:
///
/// \brief iterator inequality operator
/// \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 {
return _set != it._set or _i != it._i;
}

View File

@@ -43,19 +43,18 @@ namespace fennec
/// \brief Tuple, holds a collection of values of different types
/// \details
/// | Property | Value |
/// |:-----------:|:----------:|
/// |:-----------:|:-----------:|
/// | stable | ⛔ |
/// | dynamic | ✅ |
/// | homogeneous | ⛔ |
/// | distinct | ⛔ |
/// | ordered | ⛔ |
/// | space | \f$O(N)\f$ |
/// | linear | ✅ |
/// | access | \f$O(1)\f$ |
/// | find | \f$O(1)\f$ |
/// | space | \emph{O(N)} |
/// | access | \emph{O(1)} |
/// | find | \emph{O(1)} |
/// | insertion | ⛔ |
/// | deletion | ⛔ |
/// | space | \f$O(N)\f$ |
///
/// \tparam TypesT The types to store
template<typename...TypesT> struct tuple;
@@ -65,7 +64,7 @@ template<typename...TypesT> struct tuple;
/// \tparam i the index
/// \tparam TypesT the types held in 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>
constexpr typename tuple<TypesT...>::template elem_t<i>& get(tuple<TypesT...>& x) {
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 TypesT the types held in 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>
constexpr const typename tuple<TypesT...>::template elem_t<i>& get(const tuple<TypesT...>& x) {
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
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
@@ -114,7 +113,7 @@ public:
/// \param args The arguments to initialize the tuple with
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
template<typename...ArgsT>
tuple(ArgsT&&...args)
@@ -126,7 +125,7 @@ public:
/// \param cpy the tuple to copy
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
tuple(const tuple& cpy)
: base_t(cpy) {
@@ -137,7 +136,7 @@ public:
/// \param mov the tuple to move
///
/// \par Complexity
/// \f$O(N)\f$
/// \emph{O(N)}
///
tuple(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
/// | Property | Value |
/// |:-----------:|:----------:|
/// |:-----------:|:-----------:|
/// | stable | ✅ |
/// | dynamic | ⛔ |
/// | homogeneous | ⛔ |
/// | distinct | ⛔ |
/// | ordered | ⛔ |
/// | space | \f$O(N)\f$ |
/// | linear | ⛔ |
/// | access | \f$O(1)\f$ |
/// | space | \emph{O(1)} |
/// | access | \emph{O(1)} |
/// | find | ⛔ |
/// | insertion | \f$O(1)\f$ |
/// | deletion | \f$O(1)\f$ |
/// | space | \f$O(1)\f$ |
/// | insertion | \emph{O(1)} |
/// | deletion | \emph{O(1)} |
///
/// \tparam TypesT The types to hold in the variant
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
/// \f$O(1)\f$
/// \emph{O(1)}
///
variant()
: _bytes {}
@@ -104,13 +103,13 @@ public:
}
///
/// \brief Conversion Constructor, constructs the type in \f$TypesT\ldots\f$ that is identical to \f$T\f$
/// or the first that is constructible with \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 \emph{T}
/// \tparam T The type of the value
/// \param t The value to forward
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
template<typename 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
/// \param args The argument values
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
template<typename T, typename...ArgsT>
variant(type_identity<T>, ArgsT&&...args)
@@ -146,7 +145,7 @@ public:
/// \param v The variant to copy
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
variant(const variant& v)
: _bytes {}
@@ -169,7 +168,7 @@ public:
/// \param v The variant to move
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
variant(variant&& v) noexcept
: _bytes {}
@@ -191,7 +190,7 @@ public:
/// \brief Destructor, if a type is held, destruct it.
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
~variant() {
_clear();
@@ -211,10 +210,10 @@ public:
/// \brief value assignment operator
/// \tparam T The type 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
/// \f$O(1)\f$
/// \emph{O(1)}
///
template<typename T>
variant& operator=(T&& t) {
@@ -259,7 +258,7 @@ public:
/// \param args the argument values
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
template<typename T, typename...ArgsT> requires(contains_element_v<T, TypesT...>)
void emplace(ArgsT&&...args) {
@@ -273,7 +272,7 @@ public:
/// \param args the argument values
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
template<size_t I, typename...ArgsT>
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
/// \returns The value interpreted as \f$T\f$
/// \returns The value interpreted as \emph{T}
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
template<typename T> requires(contains_element_v<T, TypesT...>)
T& get() {
@@ -305,10 +304,10 @@ public:
///
/// \tparam T the type to interpret as
/// \returns The value interpreted as \f$T\f$
/// \returns The value interpreted as \emph{T}
///
/// \par Complexity
/// \f$O(1)\f$
/// \emph{O(1)}
///
template<typename T> requires(contains_element_v<T, TypesT...>)
const T& get() const {
@@ -317,10 +316,10 @@ public:
///
/// \tparam T the type to interpret as
/// \returns The value interpreted as \f$T\f$
/// \returns The value interpreted as \emph{T}
///
/// \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...>)
T& get() {
@@ -329,10 +328,10 @@ public:
///
/// \tparam T the type to interpret as
/// \returns The value interpreted as \f$T\f$
/// \returns The value interpreted as \emph{T}
///
/// \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...>)
const T& get() const {

View File

@@ -32,9 +32,11 @@
#ifndef FENNEC_CORE_LOGGER_H
#define FENNEC_CORE_LOGGER_H
#include <fennec/containers/pair.h>
#include <fennec/filesystem/file.h>
#include <fennec/rtti/singleton.h>
#include <fennec/containers/tuple.h>
#include <fennec/lang/system.h>
namespace fennec
{
@@ -43,6 +45,31 @@ namespace fennec
/// \brief logger class
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 =============================================================================================
public:
@@ -54,7 +81,8 @@ public:
/// \param str the string to log
/// \param _line the line of the log call
/// \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(),
const char* _file = FENNEC_BUILTIN_FILE()
) {
@@ -66,9 +94,12 @@ public:
inst._logfile.println(str);
}
const auto& color = severity_color(severity);
inst._cout->print(color.first);
inst._cout->print(cstring(_file, strlen(_file)));
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 _line the line of the log call
/// \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(),
const char* _file = FENNEC_BUILTIN_FILE()
) {
@@ -88,9 +120,13 @@ public:
inst._logfile.println(str);
}
const auto& color = severity_color(severity);
inst._cout->print(color.first);
inst._cout->print(cstring(_file, strlen(_file)));
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"
#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
#pragma warning(push)
#pragma warning(disable:4201)
@@ -59,13 +65,13 @@ public:
/// @{
union {
uint64_t num; //!< long version number
struct {
uint16_t major = { 1 }; //!< the major version
uint16_t minor = { 0 }; //!< the minor version
uint16_t patch = { 0 }; //!< the patch version
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
#endif
#ifdef FENNEC_COMPILER_CLANG
#pragma clang diagnostic pop
#endif
#if FENNEC_COMPILER_MSVC
#pragma warning(pop)
#endif

View File

@@ -39,19 +39,19 @@ namespace fennec
/// <tr><th style="vertical-align: top">Flags
/// <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
///
/// <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
///
/// <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
///
/// <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
///
/// <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
/// </table>
enum fmode_ : uint8_t
@@ -147,7 +147,7 @@ public:
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 mode the mode to open with
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 mode the mode to open with
file(const string& path, uint8_t mode)
@@ -166,7 +166,7 @@ public:
///
/// \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 mode the mode to open with
file(const path& path, uint8_t mode)
@@ -179,23 +179,39 @@ public:
/// \param file the stream to take ownership of
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
/// \details Flushes and closes an open stream
~file();
///@}
// Assignment ==========================================================================================================
public:
/// \name Assignment
/// @{
///
/// \brief Move assignment
/// \param file the stream to take ownership of
file& operator=(file&& file) noexcept;
///@}
private:
// don't allow copying streams
file(const file&) = delete;
///
/// \brief Copy Assignment
/// \details Deleted, no semantics for copying a stream. Holding multiple copies of a stream will cause conflicts.
/// \returns Deleted
file& operator=(const file&) = delete;
/// @}
// Properties ==========================================================================================================
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 {
return _handle != nullptr;
}
@@ -233,30 +249,30 @@ public:
///
/// \param path the path to the file
/// \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);
///
/// \param path the path to the file
/// \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);
///
/// \brief Open a file
/// \param path the path to the file
/// \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);
///
/// \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();
///
/// \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();
/// @}
@@ -270,12 +286,12 @@ public:
///
/// \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();
///
/// \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
/// Copies contents to the new path, and erases the old file.
@@ -288,7 +304,7 @@ public:
///
/// \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
/// Copies contents to the new path, and erases the old file.
@@ -302,7 +318,7 @@ public:
///
/// \brief Rebind the stream.
/// \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
/// Copies contents to the new path, and erases the old file.
@@ -366,16 +382,16 @@ public:
///
/// \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);
///
/// \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();
///
/// \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;
/// @}
@@ -429,13 +445,13 @@ public:
///
/// \brief put a character at the current position in the stream
/// \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);
///
/// \brief put a wide character at the current position in the stream
/// \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);
///
@@ -551,7 +567,7 @@ public:
/// \param args the argument values
template<typename...ArgsT>
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()));
}

View File

@@ -115,7 +115,7 @@ public:
///
/// \brief C-String Assignment Operator
/// \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>
path& operator=(const char (&str)[n]) {
_str = str;
@@ -125,7 +125,7 @@ public:
///
/// \brief C-String Assignment Operator
/// \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) {
_str = p;
return *this;
@@ -134,7 +134,7 @@ public:
///
/// \brief String Assignment Operator
/// \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) {
_str = p;
return *this;
@@ -143,7 +143,7 @@ public:
///
/// \brief Path Copy Assignment Operator
/// \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) {
_str = p._str;
return *this;
@@ -152,7 +152,7 @@ public:
///
/// \brief Path Move Assignment Operator
/// \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 {
_str = move(p._str);
return *this;
@@ -170,7 +170,7 @@ public:
///
/// \brief path equality operator
/// \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 {
return _str == p._str;
}
@@ -187,7 +187,7 @@ public:
///
/// \brief path append operator
/// \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 {
return path(_str + '/' + str);
}
@@ -195,7 +195,7 @@ public:
///
/// \brief path append operator
/// \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 {
return path(_str + '/' + str);
}
@@ -203,7 +203,7 @@ public:
///
/// \brief path append operator
/// \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 {
return path(_str + '/' + p._str);
}
@@ -214,7 +214,7 @@ public:
/// \brief the filename of the current path
/// \returns a string containing a copy of the filename
string filename() const {
size_t i = _str.rfind('/');
const size_t i = _str.rfind('/');
return _str.substring(i + 1);
}
@@ -227,9 +227,9 @@ public:
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() {
size_t size = _str.size();
const size_t size = _str.size();
if (size == 0) return true;
#if FENNEC_PLATFORM_WINDOWS
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
iterator begin() const {
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
iterator end() const {
return iterator(this, _str.size());
}
///
/// \brief C++ Iterator Specification \f$iterator\f$
/// \brief C++ Iterator Specification \emph{iterator}
class iterator {
public:
///
@@ -363,7 +363,7 @@ public:
///
/// \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++() {
_pos = min(_str->find('/', _pos) + 1, _str->size());
return *this;
@@ -371,9 +371,9 @@ public:
///
/// \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) {
iterator it = *this;
const iterator it = *this;
this->operator++();
return it;
}
@@ -381,7 +381,7 @@ public:
///
/// \brief iterator equality operator
/// \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 {
return _str == rhs._str and _pos == rhs._pos;
}
@@ -389,7 +389,7 @@ public:
///
/// \brief iterator inequality operator
/// \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 {
return _str != rhs._str or _pos != rhs._pos;
}

View File

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

View File

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

View File

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

View File

@@ -48,18 +48,18 @@
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// assert(expr, desc)
/// <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>
/// assertf(expr, desc)
/// <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>
/// assertd(expr, desc)
/// <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$.
/// This should be used when the branching caused by \f$assert\f$ would hinder performance in release mode.
/// 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 \emph{assert} would hinder performance in release mode.
///
/// </table>
///
@@ -92,7 +92,7 @@ void _assert(const char (&expr)[ExprL],
/// \param description the description of the assertion
#define assert(expression, description) \
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 mask the mask to and against arr
/// \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) {
if (arr == mask) {
return arr;

View File

@@ -33,23 +33,23 @@ namespace fennec
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 T1 The second type
template<typename T0, typename T1> requires has_equals_v<T0, T1>
struct equality<T0, T1> {
///
/// \brief operator to test the two values
/// \param x the value of type \f$T0\f$
/// \param y the value of type \f$T1\f$
/// \returns \f$true\f$ if equal, \f$false\f$ otherwise
/// \param x the value of type \emph{T0}
/// \param y the value of type \emph{T1}
/// \returns \emph{true} if equal, \emph{false} otherwise
constexpr bool operator()(const T0& x, const T1& y) const {
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 T1 The second type
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> {
///
/// \brief operator to test the two values
/// \param x the value of type \f$T0\f$
/// \param y the value of type \f$T1\f$
/// \returns \f$true\f$ if equal, \f$false\f$ otherwise
/// \param x the value of type \emph{T0}
/// \param y the value of type \emph{T1}
/// \returns \emph{true} if equal, \emph{false} otherwise
constexpr bool operator()(const T0& x, const T1& y) const {
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 T1 The second type
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> {
///
/// \brief operator to test the two values
/// \param x the value of type \f$T0\f$
/// \param y the value of type \f$T1\f$
/// \returns \f$true\f$ if equal, \f$false\f$ otherwise
/// \param x the value of type \emph{T0}
/// \param y the value of type \emph{T1}
/// \returns \emph{true} if equal, \emph{false} otherwise
constexpr bool operator()(const T0& x, const T1& y) const {
return not(x > y) and not(y > x);
}
@@ -93,16 +93,16 @@ struct equality<T0, T1> {
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 T1 The second type
template<typename T0, typename T1> requires has_nequals_v<T0, T1>
struct inequality<T0, T1> {
///
/// \brief operator to test the two values
/// \param x the value of type \f$T0\f$
/// \param y the value of type \f$T1\f$
/// \returns \f$true\f$ if not equal, \f$false\f$ otherwise
/// \param x the value of type \emph{T0}
/// \param y the value of type \emph{T1}
/// \returns \emph{true} if not equal, \emph{false} otherwise
constexpr bool operator()(const T0& x, const T1& y) const {
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 T1 The second type
template<typename T0, typename T1> requires has_equals_v<T0, T1>
struct inequality<T0, T1> {
///
/// \brief operator to test the two values
/// \param x the value of type \f$T0\f$
/// \param y the value of type \f$T1\f$
/// \returns \f$true\f$ if not equal, \f$false\f$ otherwise
/// \param x the value of type \emph{T0}
/// \param y the value of type \emph{T1}
/// \returns \emph{true} if not equal, \emph{false} otherwise
constexpr bool operator()(const T0& x, const T1& y) const {
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 T1 The second type
template<typename T0, typename T1> requires has_less_v<T0, T1> and has_less_v<T1, T0>
struct inequality<T0, T1> {
///
/// \brief operator to test the two values
/// \param x the value of type \f$T0\f$
/// \param y the value of type \f$T1\f$
/// \returns \f$true\f$ if not equal, \f$false\f$ otherwise
/// \param x the value of type \emph{T0}
/// \param y the value of type \emph{T1}
/// \returns \emph{true} if not equal, \emph{false} otherwise
constexpr bool operator()(const T0& x, const T1& y) const {
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 T1 The second type
template<typename T0, typename T1> requires has_greater_v<T0, T1> and has_greater_v<T1, T0>
struct inequality<T0, T1> {
///
/// \brief operator to test the two values
/// \param x the value of type \f$T0\f$
/// \param y the value of type \f$T1\f$
/// \returns \f$true\f$ if not equal, \f$false\f$ otherwise
/// \param x the value of type \emph{T0}
/// \param y the value of type \emph{T1}
/// \returns \emph{true} if not equal, \emph{false} otherwise
constexpr bool operator()(const T0& x, const T1& y) const {
return (x > y) or (y > x);
}
@@ -161,16 +161,16 @@ struct inequality<T0, T1> {
// 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 T1 The second type
template<typename T0, typename T1 = T0> requires has_less_v<T0, T1>
struct less {
///
/// \brief operator to test the two values
/// \param x the value of type \f$T0\f$
/// \param y the value of type \f$T1\f$
/// \returns \f$true\f$ if less, \f$false\f$ otherwise
/// \param x the value of type \emph{T0}
/// \param y the value of type \emph{T1}
/// \returns \emph{true} if less, \emph{false} otherwise
constexpr bool operator()(const T0& x, const T1& y) const {
return x < y;
}
@@ -180,16 +180,16 @@ struct less {
// 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 T1 The second type
template<typename T0, typename T1 = T0> requires has_less_equals_v<T0, T1>
struct less_equals {
///
/// \brief operator to test the two values
/// \param x the value of type \f$T0\f$
/// \param y the value of type \f$T1\f$
/// \returns \f$true\f$ if less than or equal, \f$false\f$ otherwise
/// \param x the value of type \emph{T0}
/// \param y the value of type \emph{T1}
/// \returns \emph{true} if less than or equal, \emph{false} otherwise
constexpr bool operator()(const T0& x, const T1& y) const {
return x <= y;
}
@@ -199,16 +199,16 @@ struct less_equals {
// 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 T1 The second type
template<typename T0, typename T1 = T0> requires has_greater_v<T0, T1>
struct greater {
///
/// \brief operator to test the two values
/// \param x the value of type \f$T0\f$
/// \param y the value of type \f$T1\f$
/// \returns \f$true\f$ if greater, \f$false\f$ otherwise
/// \param x the value of type \emph{T0}
/// \param y the value of type \emph{T1}
/// \returns \emph{true} if greater, \emph{false} otherwise
constexpr bool operator()(const T0& x, const T1& y) const {
return x > y;
}
@@ -218,16 +218,16 @@ struct greater {
// 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 T1 The second type
template<typename T0, typename T1 = T0> requires has_greater_equals_v<T0, T1>
struct greater_equals {
///
/// \brief operator to test the two values
/// \param x the value of type \f$T0\f$
/// \param y the value of type \f$T1\f$
/// \returns \f$true\f$ if greater than or equal, \f$false\f$ otherwise
/// \param x the value of type \emph{T0}
/// \param y the value of type \emph{T1}
/// \returns \emph{true} if greater than or equal, \emph{false} otherwise
constexpr bool operator()(const T0& x, const T1& y) const {
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.
/// The chosen type is stored in `fennec::conditional::type`.
/// \tparam B the value of the condition
/// \tparam TrueT type to use when \f$B == true\f$
/// \tparam FalseT type to use when \f$B == false\f$
/// \tparam TrueT type to use when \math{\textbf{B} = \textbf{true}}
/// \tparam FalseT type to use when \math{\textbf{B} = \textbf{false}}
template<bool B, typename TrueT, typename FalseT>
struct conditional;
@@ -90,12 +90,12 @@ using conditional_t
= typename conditional<B, TrueT, FalseT>::type;
#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>
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>
struct conditional<false, T, F> : type_identity<F>{};
#endif
@@ -103,13 +103,13 @@ struct conditional<false, T, F> : type_identity<F>{};
// 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
/// a boolean value is stored in `fennec::detect::is_detected` representing whether \f$DetectT<ArgsT...>\f$ is found.
/// \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 \emph{DetectT<ArgsT...>} is found.
/// \tparam DefaultT Default type
/// \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>
struct detect
{
@@ -140,7 +140,7 @@ struct detect<DefaultT, DetectT, ArgsT...>
///
/// \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**
/// \code{.cpp}
/// template<typename TypeT,

View File

@@ -41,7 +41,7 @@ namespace fennec
///
/// \brief Metaprogramming helper for testing values of type T
/// \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)) {
static_assert(detail::_declval_protector<T>{}, "declval must not be used");
return detail::_declval<T>(0);

View File

@@ -19,7 +19,6 @@
#ifndef FENNEC_LANG_DETAIL_TYPE_TRAITS_H
#define FENNEC_LANG_DETAIL_TYPE_TRAITS_H
#include <fennec/lang/ranges.h>
#include <fennec/lang/constants.h>
#include <fennec/lang/declval.h>
@@ -82,6 +81,12 @@ namespace fennec::detail
template<typename> struct _is_rvalue_reference : false_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 U>
static auto test(U*) -> bool_constant<sizeof(U) == sizeof(U)>;
@@ -105,13 +110,37 @@ namespace fennec::detail
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
template<typename T>
auto _is_iterable(int) -> decltype(
fennec::begin(declval<T&>()) != fennec::end(declval<T&>()),
detail::_begin(declval<T&>()) != detail::_end(declval<T&>()),
void(),
++declval<decltype(fennec::begin(declval<T&>()))&>(),
void(*fennec::begin(declval<T&>())),
++declval<decltype(detail::_begin(declval<T&>()))&>(),
void(*detail::_begin(declval<T&>())),
true_type{}
);
@@ -130,6 +159,20 @@ namespace fennec::detail
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>
auto _is_mappable(int) -> decltype(

View File

@@ -23,7 +23,7 @@
///
/// \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))
///
@@ -60,55 +60,55 @@
#undef FLT_DENORM_MIN
#undef FLT_ROUND_ERR
/// \brief Does \f$float\f$ have an infinity?
/// \brief Does \emph{float} have an infinity?
#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
/// \brief Does \f$float\f$ have a signaling NaN?
/// \brief Does \emph{float} have a signaling NaN?
#define FLT_HAS_SIGNALING_NAN 1
/// \brief Does \f$float\f$ use denormalization?
/// \brief Does \emph{float} use denormalization?
#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
/// \brief What rounding style does \f$float\f$ use?
/// \brief What rounding style does \emph{float} use?
#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
/// \brief The number of mantissa bits in \f$float\f$.
/// \brief The number of mantissa bits in \emph{float}.
#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
/// \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
/// \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
/// \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
/// \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
/// \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
/// \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
/// \brief Do arithmetics operations with \f$float\f$ trap?
/// \brief Do arithmetics operations with \emph{float} trap?
#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
/// \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)
/// \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)
/// \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)
/// \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)
/// \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)
/// \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)
/// \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)
/// \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)
#undef DBL_HAS_INFINITY
@@ -137,55 +137,55 @@
#undef DBL_DENORM_MIN
#undef DBL_ROUND_ERR
/// \brief Does \f$double\f$ have an infinity?
/// \brief Does \emph{double} have an infinity?
#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
/// \brief Does \f$double\f$ have a signaling NaN?
/// \brief Does \emph{double} have a signaling NaN?
#define DBL_HAS_SIGNALING_NAN 1
/// \brief Does \f$double\f$ use denormalization?
/// \brief Does \emph{double} use denormalization?
#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
/// \brief What rounding style does \f$double\f$ use?
/// \brief What rounding style does \emph{double} use?
#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
/// \brief The number of mantissa bits in \f$double\f$.
/// \brief The number of mantissa bits in \emph{double}.
#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
/// \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
/// \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
/// \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
/// \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
/// \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
/// \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
/// \brief Do arithmetics operations with \f$double\f$ trap?
/// \brief Do arithmetics operations with \emph{double} trap?
#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
/// \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)
/// \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)
/// \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)
/// \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)
/// \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)
/// \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)
/// \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)
/// \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)
#endif // FENNEC_LANG_FLOAT_H

View File

@@ -85,18 +85,18 @@ public:
///
/// \brief copy assignment
/// \param func the function to copy
/// \returns a reference to self
/// \returns a reference to \emph{this}
constexpr function& operator=(const function& func) = default;
///
/// \brief move assignment
/// \param func the function to capture
/// \returns a reference to self
/// \returns a reference to \emph{this}
constexpr function& operator=(function&& func) = default;
///
/// \brief null assignment
/// \returns a reference to self
/// \returns a reference to \emph{this}
constexpr function& operator=(nullptr_t) {
call = nullptr;
return *this;
@@ -105,7 +105,7 @@ public:
///
/// \brief function assignment
/// \param func the function to capture
/// \returns a reference to self
/// \returns a reference to \emph{this}
constexpr function& operator=(ReturnT (*func)(ArgsT...)) {
call = func;
return *this;
@@ -113,7 +113,7 @@ public:
///
/// \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 {
return call != nullptr;
}

View File

@@ -66,11 +66,11 @@ struct hash<PtrT*> : hash<uintptr_t> {
/// \param ptr the pointer to hash
/// \returns an integer hash for the value
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<>
struct hash<float> : hash<uint32_t> {
using type_t = float; //!< the type of the hash
@@ -82,6 +82,7 @@ struct hash<float> : hash<uint32_t> {
}
};
/// \brief Hashing for `double`
template<>
struct hash<double> : hash<uint64_t> {
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.
///
/// 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))
///
@@ -53,212 +53,212 @@
#undef ULLONG_MIN
#undef ULLONG_MAX
/// \brief Is \f$char\f$ signed?
/// \brief Is \emph{char} signed?
#define CHAR_IS_SIGNED true
/// \brief Rounding style of type \f$char\f$.
#define CHAR_ROUNDS 0x0
/// \brief Number of radix digits represented by \f$char\f$.
/// \brief Rounding style of type \emph{char}.
#define CHAR_ROUNDS 0
/// \brief Number of radix digits represented by \emph{char}.
#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
/// \brief Number of decimal digits necessary to differentiate all values of type \f$char\f$.
#define CHAR_DECIMAL_DIG 0x0
/// \brief The radix, or integer base, used to represent a \f$char\f$.
/// \brief Number of decimal digits necessary to differentiate all values of type \emph{char}.
#define CHAR_DECIMAL_DIG 0
/// \brief The radix, or integer base, used to represent a \emph{char}.
#define CHAR_RADIX 0x2
/// \brief Do arithmetics operations with \f$char\f$ trap?
#define CHAR_TRAPS 0xtrue
/// \brief Smallest finite value of \f$char\f$.
#define CHAR_MIN 0x80
/// \brief Largest finite value of \f$char\f$.
/// \brief Do arithmetics operations with \emph{char} trap?
#define CHAR_TRAPS true
/// \brief Smallest finite value of \emph{char}.
#define CHAR_MIN -0x80
/// \brief Largest finite value of \emph{char}.
#define CHAR_MAX 0x7f
/// \brief Is \f$wchar_t\f$ signed?
/// \brief Is \emph{wchar_t} signed?
#define WCHAR_IS_SIGNED true
/// \brief Rounding style of type \f$wchar_t\f$.
#define WCHAR_ROUNDS 0x0
/// \brief Number of radix digits represented by \f$wchar_t\f$.
/// \brief Rounding style of type \emph{wchar_t}.
#define WCHAR_ROUNDS 0
/// \brief Number of radix digits represented by \emph{wchar_t}.
#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
/// \brief Number of decimal digits necessary to differentiate all values of type \f$wchar_t\f$.
#define WCHAR_DECIMAL_DIG 0x0
/// \brief The radix, or integer base, used to represent a \f$wchar_t\f$.
/// \brief Number of decimal digits necessary to differentiate all values of type \emph{wchar_t}.
#define WCHAR_DECIMAL_DIG 0
/// \brief The radix, or integer base, used to represent a \emph{wchar_t}.
#define WCHAR_RADIX 0x2
/// \brief Do arithmetics operations with \f$wchar_t\f$ trap?
#define WCHAR_TRAPS 0xtrue
/// \brief Smallest finite value of \f$wchar_t\f$.
#define WCHAR_MIN 0x80000000
/// \brief Largest finite value of \f$wchar_t\f$.
#define WCHAR_MAX 0x7fffffff
/// \brief Do arithmetics operations with \emph{wchar_t} trap?
#define WCHAR_TRAPS true
/// \brief Smallest finite value of \emph{wchar_t}.
#define WCHAR_MIN - 0x0
/// \brief Largest finite value of \emph{wchar_t}.
#define WCHAR_MAX 0xffff
/// \brief Is \f$signed char\f$ signed?
#define SCHAR_ROUNDS 0x0
/// \brief Rounding style of type \f$signed char\f$.
/// \brief Rounding style of type \emph{signed char}.
#define SCHAR_ROUNDS 0
/// \brief Number of radix digits represented by \emph{signed char}.
#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
/// \brief Number of decimal digits represented by \f$signed char\f$.
#define SCHAR_DECIMAL_DIG 0x0
/// \brief Number of decimal digits necessary to differentiate all values of type \f$signed char\f$.
/// \brief Number of decimal digits necessary to differentiate all values of type \emph{signed char}.
#define SCHAR_DECIMAL_DIG 0
/// \brief The radix, or integer base, used to represent a \emph{signed char}.
#define SCHAR_RADIX 0x2
/// \brief Do arithmetics operations with \f$signed char\f$ trap?
#define SCHAR_TRAPS 0xtrue
/// \brief Smallest finite value of \f$signed char\f$.
#define SCHAR_MIN 0x80
/// \brief Largest finite value of \f$signed char\f$.
/// \brief Do arithmetics operations with \emph{signed char} trap?
#define SCHAR_TRAPS true
/// \brief Smallest finite value of \emph{signed char}.
#define SCHAR_MIN -0x80
/// \brief Largest finite value of \emph{signed char}.
#define SCHAR_MAX 0x7f
/// \brief Is \f$unsigned char\f$ unsigned?
#define UCHAR_ROUNDS 0x0
/// \brief Rounding style of type \f$unsigned char\f$.
/// \brief Rounding style of type \emph{unsigned char}.
#define UCHAR_ROUNDS 0
/// \brief Number of radix digits represented by \emph{unsigned char}.
#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
/// \brief Number of decimal digits represented by \f$unsigned char\f$.
#define UCHAR_DECIMAL_DIG 0x0
/// \brief Number of decimal digits necessary to differentiate all values of type \f$unsigned char\f$.
/// \brief Number of decimal digits necessary to differentiate all values of type \emph{unsigned char}.
#define UCHAR_DECIMAL_DIG 0
/// \brief The radix, or integer base, used to represent an \emph{unsigned char}.
#define UCHAR_RADIX 0x2
/// \brief Do arithmetics operations with \f$unsigned char\f$ trap?
#define UCHAR_TRAPS 0xtrue
/// \brief Smallest finite value of \f$unsigned char\f$.
/// \brief Do arithmetics operations with \emph{unsigned char} trap?
#define UCHAR_TRAPS true
/// \brief Smallest finite value of \emph{unsigned char}.
#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
/// \brief Rounding style of type \f$short\f$.
#define SHORT_ROUNDS 0x0
/// \brief Number of radix digits represented by \f$short\f$.
/// \brief Rounding style of type \emph{short}.
#define SHORT_ROUNDS 0
/// \brief Number of radix digits represented by \emph{short}.
#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
/// \brief Number of decimal digits necessary to differentiate all values of type \f$short\f$.
#define SHORT_DECIMAL_DIG 0x0
/// \brief The radix, or integer base, used to represent a \f$short\f$.
/// \brief Number of decimal digits necessary to differentiate all values of type \emph{short}.
#define SHORT_DECIMAL_DIG 0
/// \brief The radix, or integer base, used to represent a \emph{short}.
#define SHORT_RADIX 0x2
/// \brief Do arithmetics operations with \f$short\f$ trap?
#define SHORT_TRAPS 0xtrue
/// \brief Smallest finite value of \f$short\f$.
#define SHORT_MIN 0xffff8000
/// \brief Largest finite value of \f$short\f$.
/// \brief Do arithmetics operations with \emph{short} trap?
#define SHORT_TRAPS true
/// \brief Smallest finite value of \emph{short}.
#define SHORT_MIN 0x8000
/// \brief Largest finite value of \emph{short}.
#define SHORT_MAX 0x7fff
/// \brief Rounding style of type \f$unsigned short\f$.
#define USHORT_ROUNDS 0x0
/// \brief Number of radix digits represented by \f$unsigned short\f$.
/// \brief Rounding style of type \emph{unsigned short}.
#define USHORT_ROUNDS 0
/// \brief Number of radix digits represented by \emph{unsigned short}.
#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
/// \brief Number of decimal digits necessary to differentiate all values of type \f$unsigned short\f$.
#define USHORT_DECIMAL_DIG 0x0
/// \brief The radix, or integer base, used to represent a \f$unsigned short\f$.
/// \brief Number of decimal digits necessary to differentiate all values of type \emph{unsigned short}.
#define USHORT_DECIMAL_DIG 0
/// \brief The radix, or integer base, used to represent an \emph{unsigned short}.
#define USHORT_RADIX 0x2
/// \brief Do arithmetics operations with \f$unsigned short\f$ trap?
#define USHORT_TRAPS 0xtrue
/// \brief Smallest finite value of \f$unsigned short\f$.
#define USHORT_MIN 0x0
/// \brief Largest finite value of \f$unsigned short\f$.
/// \brief Do arithmetics operations with \emph{unsigned short} trap?
#define USHORT_TRAPS true
/// \brief Smallest finite value of \emph{unsigned short}.
#define USHORT_MIN 0
/// \brief Largest finite value of \emph{unsigned short}.
#define USHORT_MAX 0xffff
/// \brief Rounding style of type \f$int\f$.
#define INT_ROUNDS 0x0
/// \brief Number of radix digits represented by \f$int\f$.
/// \brief Rounding style of type \emph{int}.
#define INT_ROUNDS 0
/// \brief Number of radix digits represented by \emph{int}.
#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
/// \brief Number of decimal digits necessary to differentiate all values of type \f$int\f$.
#define INT_DECIMAL_DIG 0x0
/// \brief The radix, or integer base, used to represent a \f$int\f$.
/// \brief Number of decimal digits necessary to differentiate all values of type \emph{int}.
#define INT_DECIMAL_DIG 0
/// \brief The radix, or integer base, used to represent an \emph{int}.
#define INT_RADIX 0x2
/// \brief Do arithmetics operations with \f$int\f$ trap?
#define INT_TRAPS 0xtrue
/// \brief Smallest finite value of \f$int\f$.
/// \brief Do arithmetics operations with \emph{int} trap?
#define INT_TRAPS true
/// \brief Smallest finite value of \emph{int}.
#define INT_MIN 0x80000000
/// \brief Largest finite value of \f$int\f$.
/// \brief Largest finite value of \emph{int}.
#define INT_MAX 0x7fffffff
/// \brief Rounding style of type \f$unsigned int\f$.
#define UINT_ROUNDS 0x0
/// \brief Number of radix digits represented by \f$unsigned int\f$.
/// \brief Rounding style of type \emph{unsigned int}.
#define UINT_ROUNDS 0
/// \brief Number of radix digits represented by \emph{unsigned int}.
#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
/// \brief Number of decimal digits necessary to differentiate all values of type \f$unsigned int\f$.
#define UINT_DECIMAL_DIG 0x0
/// \brief The radix, or unsigned integer base, used to represent a \f$unsigned int\f$.
/// \brief Number of decimal digits necessary to differentiate all values of type \emph{unsigned int}.
#define UINT_DECIMAL_DIG 0
/// \brief The radix, or integer base, used to represent an \emph{unsigned int}.
#define UINT_RADIX 0x2
/// \brief Do arithmetics operations with \f$unsigned int\f$ trap?
#define UINT_TRAPS 0xtrue
/// \brief Smallest finite value of \f$unsigned int\f$.
#define UINT_MIN 0x0
/// \brief Largest finite value of \f$unsigned int\f$.
/// \brief Do arithmetics operations with \emph{unsigned int} trap?
#define UINT_TRAPS true
/// \brief Smallest finite value of \emph{unsigned int}.
#define UINT_MIN 0
/// \brief Largest finite value of \emph{unsigned int}.
#define UINT_MAX 0xffffffff
/// \brief Rounding style of type \f$long int\f$.
#define LONG_ROUNDS 0x0
/// \brief Number of radix digits represented by \f$long int\f$.
/// \brief Rounding style of type \emph{long int}.
#define LONG_ROUNDS 0
/// \brief Number of radix digits represented by \emph{long int}.
#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
/// \brief Number of decimal digits necessary to differentiate all values of type \f$long int\f$.
#define LONG_DECIMAL_DIG 0x0
/// \brief The radix, or long integer base, used to represent a \f$long int\f$.
/// \brief Number of decimal digits necessary to differentiate all values of type \emph{long int}.
#define LONG_DECIMAL_DIG 0
/// \brief The radix, or integer base, used to represent a \emph{long int}.
#define LONG_RADIX 0x2
/// \brief Do arithmetics operations with \f$long int\f$ trap?
#define LONG_TRAPS 0xtrue
/// \brief Smallest finite value of \f$long int\f$.
/// \brief Do arithmetics operations with \emph{long int} trap?
#define LONG_TRAPS true
/// \brief Smallest finite value of \emph{long int}.
#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
/// \brief Rounding style of type \f$unsigned long int\f$.
#define ULONG_ROUNDS 0x0
/// \brief Number of radix digits represented by \f$unsigned long int\f$.
/// \brief Rounding style of type \emph{unsigned long int}.
#define ULONG_ROUNDS 0
/// \brief Number of radix digits represented by \emph{unsigned long int}.
#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
/// \brief Number of decimal digits necessary to differentiate all values of type \f$unsigned long int\f$.
#define ULONG_DECIMAL_DIG 0x0
/// \brief The radix, or unsigned long integer base, used to represent a \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 0
/// \brief The radix, or integer base, used to represent an \emph{unsigned long int}.
#define ULONG_RADIX 0x2
/// \brief Do arithmetics operations with \f$unsigned long int\f$ trap?
#define ULONG_TRAPS 0xtrue
/// \brief Smallest finite value of \f$unsigned long int\f$.
#define ULONG_MIN 0x0
/// \brief Largest finite value of \f$unsigned long int\f$.
/// \brief Do arithmetics operations with \emph{unsigned long int} trap?
#define ULONG_TRAPS true
/// \brief Smallest finite value of \emph{unsigned long int}.
#define ULONG_MIN 0
/// \brief Largest finite value of \emph{unsigned long int}.
#define ULONG_MAX 0xffffffffffffffff
/// \brief Rounding style of type \f$long long\f$.
#define LLONG_ROUNDS 0x0
/// \brief Number of radix digits represented by \f$long long\f$.
/// \brief Rounding style of type \emph{long long}.
#define LLONG_ROUNDS 0
/// \brief Number of radix digits represented by \emph{long long}.
#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
/// \brief Number of decimal digits necessary to differentiate all values of type \f$long long\f$.
#define LLONG_DECIMAL_DIG 0x0
/// \brief The radix, or long longeger base, used to represent a \f$long long\f$.
/// \brief Number of decimal digits necessary to differentiate all values of type \emph{long long}.
#define LLONG_DECIMAL_DIG 0
/// \brief The radix, or integer base, used to represent a \emph{long long}.
#define LLONG_RADIX 0x2
/// \brief Do arithmetics operations with \f$long long\f$ trap?
#define LLONG_TRAPS 0xtrue
/// \brief Smallest finite value of \f$long long\f$.
/// \brief Do arithmetics operations with \emph{long long} trap?
#define LLONG_TRAPS true
/// \brief Smallest finite value of \emph{long long}.
#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
/// \brief Rounding style of type \f$unsigned long long\f$.
#define ULLONG_ROUNDS 0x0
/// \brief Number of radix digits represented by \f$unsigned long long\f$.
/// \brief Rounding style of type \emph{unsigned long long}.
#define ULLONG_ROUNDS 0
/// \brief Number of radix digits represented by \emph{unsigned long long}.
#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
/// \brief Number of decimal digits necessary to differentiate all values of type \f$unsigned long long\f$.
#define ULLONG_DECIMAL_DIG 0x0
/// \brief The radix, or unsigned long longeger base, used to represent a \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 0
/// \brief The radix, or integer base, used to represent an \emph{unsigned long long}.
#define ULLONG_RADIX 0x2
/// \brief Do arithmetics operations with \f$unsigned long long\f$ trap?
#define ULLONG_TRAPS 0xtrue
/// \brief Smallest finite value of \f$unsigned long long\f$.
#define ULLONG_MIN 0x0
/// \brief Largest finite value of \f$unsigned long long\f$.
/// \brief Do arithmetics operations with \emph{unsigned long long} trap?
#define ULLONG_TRAPS true
/// \brief Smallest finite value of \emph{unsigned long long}.
#define ULLONG_MIN 0
/// \brief Largest finite value of \emph{unsigned long long}.
#define ULLONG_MAX 0xffffffffffffffff
#endif // FENNEC_LANG_INTEGER_H

View File

@@ -40,59 +40,59 @@
/// <tr><th style="vertical-align: top">Syntax
/// <th style="vertical-align: top">Description
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \f$FENNEC_HAS_BUILTIN_BIT_CAST\f$ <br>
/// \f$Y FENNEC_BUILTIN_BIT_CAST(X)\f$
/// \emph{FENNEC_HAS_BUILTIN_BIT_CAST} <br>
/// \emph{Y FENNEC_BUILTIN_BIT_CAST(X)}
/// <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>
/// \f$FENNEC_HAS_BUILTIN_ADDRESSOF\f$ <br>
/// \f$Y FENNEC_BUILTIN_ADDRESSOF(X)\f$
/// \emph{FENNEC_HAS_BUILTIN_ADDRESSOF} <br>
/// \emph{Y FENNEC_BUILTIN_ADDRESSOF(X)}
/// <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>
/// \f$FENNEC_HAS_BUILTIN_IS_CONVERTIBLE\f$ <br>
/// \f$B FENNEC_BUILTIN_IS_CONVERTIBLE(X, Y)\f$
/// \emph{FENNEC_HAS_BUILTIN_IS_CONVERTIBLE} <br>
/// \emph{B FENNEC_BUILTIN_IS_CONVERTIBLE(X, Y)}
/// <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>
/// \f$FENNEC_HAS_BUILTIN_IS_EMPTY\f$ <br>
/// \f$B FENNEC_BUILTIN_IS_EMPTY(X)\f$
/// \emph{FENNEC_HAS_BUILTIN_IS_EMPTY} <br>
/// \emph{B FENNEC_BUILTIN_IS_EMPTY(X)}
/// <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>
/// \f$FENNEC_HAS_BUILTIN_IS_POLYMORPHIC\f$ <br>
/// \f$B FENNEC_BUILTIN_IS_POLYMORPHIC(X)\f$
/// \emph{FENNEC_HAS_BUILTIN_IS_POLYMORPHIC} <br>
/// \emph{B FENNEC_BUILTIN_IS_POLYMORPHIC(X)}
/// <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>
/// \f$FENNEC_HAS_BUILTIN_IS_FINAL\f$ <br>
/// \f$B FENNEC_BUILTIN_IS_FINAL(X)\f$
/// \emph{FENNEC_HAS_BUILTIN_IS_FINAL} <br>
/// \emph{B FENNEC_BUILTIN_IS_FINAL(X)}
/// <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>
/// \f$FENNEC_HAS_BUILTIN_IS_ABSTRACT\f$ <br>
/// \f$B FENNEC_BUILTIN_IS_ABSTRACT(X)\f$
/// \emph{FENNEC_HAS_BUILTIN_IS_ABSTRACT} <br>
/// \emph{B FENNEC_BUILTIN_IS_ABSTRACT(X)}
/// <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>
/// \f$FENNEC_HAS_BUILTIN_IS_STANDARD_LAYOUT\f$ <br>
/// \f$B FENNEC_BUILTIN_IS_STANDARD_LAYOUT(X)\f$
/// \emph{FENNEC_HAS_BUILTIN_IS_STANDARD_LAYOUT} <br>
/// \emph{B FENNEC_BUILTIN_IS_STANDARD_LAYOUT(X)}
/// <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
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \f$FENNEC_HAS_BUILTIN_IS_CONSTRUCTIBLE\f$ <br>
/// \f$B FENNEC_BUILTIN_IS_CONSTRUCTIBLE(X, ...)\f$
/// \emph{FENNEC_HAS_BUILTIN_IS_CONSTRUCTIBLE} <br>
/// \emph{B FENNEC_BUILTIN_IS_CONSTRUCTIBLE(X, ...)}
/// <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>
///
@@ -242,8 +242,16 @@
// Difficult and Inconsistent without intrinsics
#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_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE(type) __has_trivial_destructor(type)
# define FENNEC_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE(type) __is_trivially_destructible(type)
#else
# define FENNEC_HAS_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE 0
#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_denorm = false; //!< Check if TypeT denormalizes
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_modulo = false; //!< Check if TypeT can handle modulo arithmetic
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
};
// Overload definitions for basic types
// Overload for the builtin floating point type
// Overloads ===========================================================================================================
///
/// \brief Definition for type \emph{float}.
template<> struct numeric_limits<float>
{
static constexpr bool is_specialized = true;
static constexpr bool is_signed = true;
static constexpr bool is_integer = false;
static constexpr bool is_exact = false;
static constexpr bool has_infinity = FLT_HAS_INFINITY;
static constexpr bool has_quiet_nan = FLT_HAS_QUIET_NAN;
static constexpr bool has_signaling_nan = FLT_HAS_SIGNALING_NAN;
static constexpr bool has_denorm = FLT_HAS_DENORM;
static constexpr bool has_denorm_loss = FLT_HAS_DENORM_LOSS;
static constexpr bool is_iec559 = FLT_IS_IEC559;
static constexpr bool is_bounded = true;
static constexpr bool is_modulo = false;
static constexpr bool tinyness_before = FLT_TINYNESS_BEFORE;
static constexpr bool traps = FLT_TRAPS;
static constexpr bool is_specialized = true; //!< Check if the template is specialized for float
static constexpr bool is_signed = true; //!< Check if float is signed
static constexpr bool is_integer = false; //!< Check if float is of an integral type
static constexpr bool is_exact = false; //!< Check if float is exact in its precision
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; //!< Check if float can hold a non-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; //!< Check if float denormalizes
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; //!< Check if float represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; //!< Check if float represents a finite set of values
static constexpr bool is_modulo = false; //!< Check if float can handle modulo arithmetic
static constexpr bool tinyness_before = FLT_TINYNESS_BEFORE; //!< Check if float checks for tinyness before rounding
static constexpr bool traps = FLT_TRAPS; //!< Check if float can cause operations to trap
static constexpr int digits = FLT_MANT_DIG;
static constexpr int digits10 = FLT_DIG;
static constexpr int max_digits10 = FLT_DECIMAL_DIG;
static constexpr int radix = FLT_RADIX;
static constexpr int min_exponent = FLT_MIN_EXP;
static constexpr int min_exponent10 = FLT_MIN_10_EXP;
static constexpr int max_exponent = FLT_MAX_EXP;
static constexpr int max_exponent10 = FLT_MAX_10_EXP;
static constexpr int digits = FLT_MANT_DIG; //!< Get the base representation of the type
static constexpr int digits10 = FLT_DIG; //!< Get the number of radix digits float represents
static constexpr int max_digits10 = FLT_DECIMAL_DIG; //!< Get the number of decimal digits float represents
static constexpr int radix = FLT_RADIX; //!< Get the maximum number of decimal digits float represents
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; //!< Get the minimum number of decimal digits that represent the exponent of float
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; //!< Get the maximum number of decimal digits that represent the exponent of float
static constexpr float min() { return -FLT_MAX; }
static constexpr float max() { return FLT_MAX; }
static constexpr float lowest() { return FLT_MIN; }
static constexpr float epsilon() { return FLT_EPSILON; }
static constexpr float round_error() { return FLT_ROUND_ERR; }
static constexpr float infinity() { return FLT_INF; }
static constexpr float quiet_NaN() { return FLT_QUIET_NAN; }
static constexpr float signaling_NaN() { return FLT_SIGNALING_NAN; }
static constexpr float denorm_min() { return FLT_DENORM_MIN; }
static constexpr float min() { return -FLT_MAX; } //!< \returns the minimum finite value of float
static constexpr float max() { return FLT_MAX; } //!< \returns the maximum finite value of float
static constexpr float lowest() { return FLT_MIN; } //!< \returns the smallest positive value of float
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; } //!< \returns the max rounding error of float
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; } //!< \returns a value of float holding a quiet 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; } //!< \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>
{
static constexpr bool is_specialized = true;
static constexpr bool is_signed = true;
static constexpr bool is_integer = false;
static constexpr bool is_exact = false;
static constexpr bool has_infinity = DBL_HAS_INFINITY;
static constexpr bool has_quiet_nan = DBL_HAS_QUIET_NAN;
static constexpr bool has_signaling_nan = DBL_HAS_SIGNALING_NAN;
static constexpr bool has_denorm = DBL_HAS_DENORM;
static constexpr bool has_denorm_loss = DBL_HAS_DENORM_LOSS;
static constexpr bool is_iec559 = DBL_IS_IEC559;
static constexpr bool is_bounded = true;
static constexpr bool is_modulo = false;
static constexpr bool tinyness_before = DBL_TINYNESS_BEFORE;
static constexpr bool traps = DBL_TRAPS;
static constexpr bool is_specialized = true; //!< Check if the template is specialized for double
static constexpr bool is_signed = true; //!< Check if double is signed
static constexpr bool is_integer = false; //!< Check if double is of an integral type
static constexpr bool is_exact = false; //!< Check if double is exact in its precision
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; //!< Check if double can hold a non-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; //!< Check if double denormalizes
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; //!< Check if double represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; //!< Check if double represents a finite set of values
static constexpr bool is_modulo = false; //!< Check if double can handle modulo arithmetic
static constexpr bool tinyness_before = DBL_TINYNESS_BEFORE; //!< Check if double checks for tinyness before rounding
static constexpr bool traps = DBL_TRAPS; //!< Check if double can cause operations to trap
static constexpr int digits = DBL_MANT_DIG;
static constexpr int digits10 = DBL_DIG;
static constexpr int max_digits10 = DBL_DECIMAL_DIG;
static constexpr int radix = DBL_RADIX;
static constexpr int min_exponent = DBL_MIN_EXP;
static constexpr int min_exponent10 = DBL_MIN_10_EXP;
static constexpr int max_exponent = DBL_MAX_EXP;
static constexpr int max_exponent10 = DBL_MAX_10_EXP;
static constexpr int digits = DBL_MANT_DIG; //!< Get the base representation of the type
static constexpr int digits10 = DBL_DIG; //!< Get the number of radix digits double represents
static constexpr int max_digits10 = DBL_DECIMAL_DIG; //!< Get the number of decimal digits double represents
static constexpr int radix = DBL_RADIX; //!< Get the maximum number of decimal digits double represents
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; //!< Get the minimum number of decimal digits that represent the exponent of double
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; //!< Get the maximum number of decimal digits that represent the exponent of double
static constexpr double min() { return -DBL_MAX; }
static constexpr double max() { return DBL_MAX; }
static constexpr double lowest() { return DBL_MIN; }
static constexpr double epsilon() { return DBL_EPSILON; }
static constexpr double round_error() { return DBL_ROUND_ERR; }
static constexpr double infinity() { return DBL_INF; }
static constexpr double quiet_NaN() { return DBL_QUIET_NAN; }
static constexpr double signaling_NaN() { return DBL_SIGNALING_NAN; }
static constexpr double denorm_min() { return DBL_DENORM_MIN; }
static constexpr double min() { return -DBL_MAX; } //!< \returns the minimum finite value of double
static constexpr double max() { return DBL_MAX; } //!< \returns the maximum finite value of double
static constexpr double lowest() { return DBL_MIN; } //!< \returns the smallest positive value of double
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; } //!< \returns the max rounding error of double
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; } //!< \returns a value of double holding a quiet 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; } //!< \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>
{
static constexpr bool is_specialized = true;
static constexpr bool is_signed = CHAR_IS_SIGNED;
static constexpr bool is_integer = true;
static constexpr bool is_exact = true;
static constexpr bool has_infinity = false;
static constexpr bool has_quiet_nan = false;
static constexpr bool has_signaling_nan = false;
static constexpr bool has_denorm = false;
static constexpr bool has_denorm_loss = false;
static constexpr bool is_iec559 = false;
static constexpr bool is_bounded = true;
static constexpr bool is_modulo = true;
static constexpr bool tinyness_before = false;
static constexpr bool traps = true;
static constexpr bool is_specialized = true; //!< Check if the template is specialized for char
static constexpr bool is_signed = CHAR_IS_SIGNED; //!< Check if char is signed
static constexpr bool is_integer = true; //!< Check if char is of an integral type
static constexpr bool is_exact = true; //!< Check if char is exact in its precision
static constexpr bool has_infinity = false; //!< Check if char can hold a value representing infinity
static constexpr bool has_quiet_nan = false; //!< Check if char can hold a non-signaling nan
static constexpr bool has_signaling_nan = false; //!< Check if char can hold a signaling nan
static constexpr bool has_denorm = false; //!< Check if char denormalizes
static constexpr bool has_denorm_loss = false; //!< Check if char has precision loss when denormalized
static constexpr bool is_iec559 = false; //!< Check if char represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; //!< Check if char represents a finite set of values
static constexpr bool is_modulo = true; //!< Check if char can handle modulo arithmetic
static constexpr bool tinyness_before = false; //!< Check if char checks for tinyness before rounding
static constexpr bool traps = true; //!< Check if char can cause operations to trap
static constexpr int digits = CHAR_RADIX_DIG;
static constexpr int digits10 = CHAR_DIG;
static constexpr int max_digits10 = CHAR_DECIMAL_DIG;
static constexpr int radix = CHAR_RADIX;
static constexpr int min_exponent = 0;
static constexpr int min_exponent10 = 0;
static constexpr int max_exponent = 0;
static constexpr int max_exponent10 = 0;
static constexpr int digits = CHAR_RADIX_DIG; //!< Get the base representation of the type
static constexpr int digits10 = CHAR_DIG; //!< Get the number of radix digits char represents
static constexpr int max_digits10 = CHAR_DECIMAL_DIG; //!< Get the number of decimal digits char represents
static constexpr int radix = CHAR_RADIX; //!< Get the maximum number of decimal digits char represents
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; //!< Get the minimum number of decimal digits that represent the exponent of char
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; //!< 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 max() { return CHAR_MAX; }
static constexpr char lowest() { return 1; }
static constexpr char epsilon() { return 1; }
static constexpr char round_error() { return 0; }
static constexpr char infinity() { return 0; }
static constexpr char quiet_NaN() { return 0; }
static constexpr char signaling_NaN() { return 0; }
static constexpr char denorm_min() { return 0; }
static constexpr char min() { return CHAR_MIN; } //!< \returns the minimum finite value of char
static constexpr char max() { return CHAR_MAX; } //!< \returns the maximum finite value of char
static constexpr char lowest() { return 1; } //!< \returns the smallest positive value of char
static constexpr char epsilon() { return 1; } //!< \returns the difference between 1.0 and the next representable value
static constexpr char round_error() { return 0; } //!< \returns the max rounding error of char
static constexpr char infinity() { return 0; } //!< \returns a value of char holding a positive infinity
static constexpr char quiet_NaN() { return 0; } //!< \returns a value of char holding a quiet NaN
static constexpr char signaling_NaN() { return 0; } //!< \returns a value of char holding a signaling NaN
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>
{
static constexpr bool is_specialized = true;
static constexpr bool is_signed = true;
static constexpr bool is_integer = true;
static constexpr bool is_exact = true;
static constexpr bool has_infinity = false;
static constexpr bool has_quiet_nan = false;
static constexpr bool has_signaling_nan = false;
static constexpr bool has_denorm = false;
static constexpr bool has_denorm_loss = false;
static constexpr bool is_iec559 = false;
static constexpr bool is_bounded = true;
static constexpr bool is_modulo = true;
static constexpr bool tinyness_before = false;
static constexpr bool traps = true;
static constexpr bool is_specialized = true; //!< Check if the template is specialized for signed char
static constexpr bool is_signed = true; //!< Check if signed char is signed
static constexpr bool is_integer = true; //!< Check if signed char is of an integral type
static constexpr bool is_exact = true; //!< Check if signed char is exact in its precision
static constexpr bool has_infinity = false; //!< Check if signed char can hold a value representing infinity
static constexpr bool has_quiet_nan = false; //!< Check if signed char can hold a non-signaling nan
static constexpr bool has_signaling_nan = false; //!< Check if signed char can hold a signaling nan
static constexpr bool has_denorm = false; //!< Check if signed char denormalizes
static constexpr bool has_denorm_loss = false; //!< Check if signed char has precision loss when denormalized
static constexpr bool is_iec559 = false; //!< Check if signed char represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; //!< Check if signed char represents a finite set of values
static constexpr bool is_modulo = true; //!< Check if signed char can handle modulo arithmetic
static constexpr bool tinyness_before = false; //!< Check if signed char checks for tinyness before rounding
static constexpr bool traps = true; //!< Check if signed char can cause operations to trap
static constexpr int digits = SCHAR_RADIX_DIG;
static constexpr int digits10 = SCHAR_DIG;
static constexpr int max_digits10 = SCHAR_DECIMAL_DIG;
static constexpr int radix = SCHAR_RADIX;
static constexpr int min_exponent = 0;
static constexpr int min_exponent10 = 0;
static constexpr int max_exponent = 0;
static constexpr int max_exponent10 = 0;
static constexpr int digits = SCHAR_RADIX_DIG; //!< Get the base representation of the type
static constexpr int digits10 = SCHAR_DIG; //!< Get the number of radix digits signed char represents
static constexpr int max_digits10 = SCHAR_DECIMAL_DIG; //!< Get the number of decimal digits signed char represents
static constexpr int radix = SCHAR_RADIX; //!< Get the maximum number of decimal digits signed char represents
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; //!< Get the minimum number of decimal digits that represent the exponent of signed char
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; //!< 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 max() { return SCHAR_MAX; }
static constexpr signed char lowest() { return 1; }
static constexpr signed char epsilon() { return 1; }
static constexpr signed char round_error() { return 0; }
static constexpr signed char infinity() { return 0; }
static constexpr signed char quiet_NaN() { return 0; }
static constexpr signed char signaling_NaN() { return 0; }
static constexpr signed char denorm_min() { return 0; }
static constexpr signed char min() { return SCHAR_MIN; } //!< \returns the minimum finite value of signed char
static constexpr signed char max() { return SCHAR_MAX; } //!< \returns the maximum finite value of signed char
static constexpr signed char lowest() { return 1; } //!< \returns the smallest positive value of signed char
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; } //!< \returns the max rounding error of signed char
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; } //!< \returns a value of signed char holding a quiet NaN
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; } //!< \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>
{
static constexpr bool is_specialized = true;
static constexpr bool is_signed = false;
static constexpr bool is_integer = true;
static constexpr bool is_exact = true;
static constexpr bool has_infinity = false;
static constexpr bool has_quiet_nan = false;
static constexpr bool has_signaling_nan = false;
static constexpr bool has_denorm = false;
static constexpr bool has_denorm_loss = false;
static constexpr bool is_iec559 = false;
static constexpr bool is_bounded = true;
static constexpr bool is_modulo = true;
static constexpr bool tinyness_before = false;
static constexpr bool traps = true;
static constexpr bool is_specialized = true; //!< Check if the template is specialized for unsigned char
static constexpr bool is_signed = false; //!< Check if unsigned char is unsigned
static constexpr bool is_integer = true; //!< Check if unsigned char is of an integral type
static constexpr bool is_exact = true; //!< Check if unsigned char is exact in its precision
static constexpr bool has_infinity = false; //!< Check if unsigned char can hold a value representing infinity
static constexpr bool has_quiet_nan = false; //!< Check if unsigned char can hold a non-signaling nan
static constexpr bool has_signaling_nan = false; //!< Check if unsigned char can hold a signaling nan
static constexpr bool has_denorm = false; //!< Check if unsigned char denormalizes
static constexpr bool has_denorm_loss = false; //!< Check if unsigned char has precision loss when denormalized
static constexpr bool is_iec559 = false; //!< Check if unsigned char represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; //!< Check if unsigned char represents a finite set of values
static constexpr bool is_modulo = true; //!< Check if unsigned char can handle modulo arithmetic
static constexpr bool tinyness_before = false; //!< Check if unsigned char checks for tinyness before rounding
static constexpr bool traps = true; //!< Check if unsigned char can cause operations to trap
static constexpr int digits = UCHAR_RADIX_DIG;
static constexpr int digits10 = UCHAR_DIG;
static constexpr int max_digits10 = UCHAR_DECIMAL_DIG;
static constexpr int radix = UCHAR_RADIX;
static constexpr int min_exponent = 0;
static constexpr int min_exponent10 = 0;
static constexpr int max_exponent = 0;
static constexpr int max_exponent10 = 0;
static constexpr int digits = UCHAR_RADIX_DIG; //!< Get the base representation of the type
static constexpr int digits10 = UCHAR_DIG; //!< Get the number of radix digits unsigned char represents
static constexpr int max_digits10 = UCHAR_DECIMAL_DIG; //!< Get the number of decimal digits unsigned char represents
static constexpr int radix = UCHAR_RADIX; //!< Get the maximum number of decimal digits unsigned char represents
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; //!< Get the minimum number of decimal digits that represent the exponent of unsigned char
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; //!< 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 max() { return UCHAR_MAX; }
static constexpr unsigned char lowest() { return 1; }
static constexpr unsigned char epsilon() { return 1; }
static constexpr unsigned char round_error() { return 0; }
static constexpr unsigned char infinity() { return 0; }
static constexpr unsigned char quiet_NaN() { return 0; }
static constexpr unsigned char signaling_NaN() { return 0; }
static constexpr unsigned char denorm_min() { return 0; }
static constexpr unsigned char min() { return UCHAR_MIN; } //!< \returns the minimum finite value of unsigned char
static constexpr unsigned char max() { return UCHAR_MAX; } //!< \returns the maximum finite value of unsigned char
static constexpr unsigned char lowest() { return 1; } //!< \returns the smallest positive value of unsigned char
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; } //!< \returns the max rounding error of unsigned char
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; } //!< \returns a value of unsigned char holding a quiet NaN
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; } //!< \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>
{
static constexpr bool is_specialized = true;
static constexpr bool is_signed = true;
static constexpr bool is_integer = true;
static constexpr bool is_exact = true;
static constexpr bool has_infinity = false;
static constexpr bool has_quiet_nan = false;
static constexpr bool has_signaling_nan = false;
static constexpr bool has_denorm = false;
static constexpr bool has_denorm_loss = false;
static constexpr bool is_iec559 = false;
static constexpr bool is_bounded = true;
static constexpr bool is_modulo = true;
static constexpr bool tinyness_before = false;
static constexpr bool traps = true;
static constexpr bool is_specialized = true; //!< Check if the template is specialized for short
static constexpr bool is_signed = true; //!< Check if short is signed
static constexpr bool is_integer = true; //!< Check if short is of an integral type
static constexpr bool is_exact = true; //!< Check if short is exact in its precision
static constexpr bool has_infinity = false; //!< Check if short can hold a value representing infinity
static constexpr bool has_quiet_nan = false; //!< Check if short can hold a non-signaling nan
static constexpr bool has_signaling_nan = false; //!< Check if short can hold a signaling nan
static constexpr bool has_denorm = false; //!< Check if short denormalizes
static constexpr bool has_denorm_loss = false; //!< Check if short has precision loss when denormalized
static constexpr bool is_iec559 = false; //!< Check if short represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; //!< Check if short represents a finite set of values
static constexpr bool is_modulo = true; //!< Check if short can handle modulo arithmetic
static constexpr bool tinyness_before = false; //!< Check if short checks for tinyness before rounding
static constexpr bool traps = true; //!< Check if short can cause operations to trap
static constexpr int digits = SHORT_RADIX_DIG;
static constexpr int digits10 = SHORT_DIG;
static constexpr int max_digits10 = SHORT_DECIMAL_DIG;
static constexpr int radix = SHORT_RADIX;
static constexpr int min_exponent = 0;
static constexpr int min_exponent10 = 0;
static constexpr int max_exponent = 0;
static constexpr int max_exponent10 = 0;
static constexpr int digits = SHORT_RADIX_DIG; //!< Get the base representation of the type
static constexpr int digits10 = SHORT_DIG; //!< Get the number of radix digits short represents
static constexpr int max_digits10 = SHORT_DECIMAL_DIG; //!< Get the number of decimal digits short represents
static constexpr int radix = SHORT_RADIX; //!< Get the maximum number of decimal digits short represents
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; //!< Get the minimum number of decimal digits that represent the exponent of short
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; //!< 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 max() { return SHORT_MAX; }
static constexpr short lowest() { return 1; }
static constexpr short epsilon() { return 1; }
static constexpr short round_error() { return 0; }
static constexpr short infinity() { return 0; }
static constexpr short quiet_NaN() { return 0; }
static constexpr short signaling_NaN() { return 0; }
static constexpr short denorm_min() { return 0; }
static constexpr short min() { return static_cast<short>(SHORT_MIN); } //!< \returns the minimum finite value of short
static constexpr short max() { return SHORT_MAX; } //!< \returns the maximum finite value of short
static constexpr short lowest() { return 1; } //!< \returns the smallest positive value of short
static constexpr short epsilon() { return 1; } //!< \returns the difference between 1.0 and the next representable value
static constexpr short round_error() { return 0; } //!< \returns the max rounding error of short
static constexpr short infinity() { return 0; } //!< \returns a value of short holding a positive infinity
static constexpr short quiet_NaN() { return 0; } //!< \returns a value of short holding a quiet NaN
static constexpr short signaling_NaN() { return 0; } //!< \returns a value of short holding a signaling NaN
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>
{
static constexpr bool is_specialized = true;
static constexpr bool is_signed = false;
static constexpr bool is_integer = true;
static constexpr bool is_exact = true;
static constexpr bool has_infinity = false;
static constexpr bool has_quiet_nan = false;
static constexpr bool has_signaling_nan = false;
static constexpr bool has_denorm = false;
static constexpr bool has_denorm_loss = false;
static constexpr bool is_iec559 = false;
static constexpr bool is_bounded = true;
static constexpr bool is_modulo = true;
static constexpr bool tinyness_before = false;
static constexpr bool traps = true;
static constexpr bool is_specialized = true; //!< Check if the template is specialized for signed short
static constexpr bool is_signed = false; //!< Check if unsigned short is signed
static constexpr bool is_integer = true; //!< Check if unsigned short is of an integral type
static constexpr bool is_exact = true; //!< Check if unsigned short is exact in its precision
static constexpr bool has_infinity = false; //!< Check if unsigned short can hold a value representing infinity
static constexpr bool has_quiet_nan = false; //!< Check if unsigned short can hold a non-signaling nan
static constexpr bool has_signaling_nan = false; //!< Check if unsigned short can hold a signaling nan
static constexpr bool has_denorm = false; //!< Check if unsigned short denormalizes
static constexpr bool has_denorm_loss = false; //!< Check if unsigned short has precision loss when denormalized
static constexpr bool is_iec559 = false; //!< Check if unsigned short represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; //!< Check if unsigned short represents a finite set of values
static constexpr bool is_modulo = true; //!< Check if unsigned short can handle modulo arithmetic
static constexpr bool tinyness_before = false; //!< Check if unsigned short checks for tinyness before rounding
static constexpr bool traps = true; //!< Check if unsigned short can cause operations to trap
static constexpr int digits = USHORT_RADIX_DIG;
static constexpr int digits10 = USHORT_DIG;
static constexpr int max_digits10 = USHORT_DECIMAL_DIG;
static constexpr int radix = USHORT_RADIX;
static constexpr int min_exponent = 0;
static constexpr int min_exponent10 = 0;
static constexpr int max_exponent = 0;
static constexpr int max_exponent10 = 0;
static constexpr int digits = USHORT_RADIX_DIG; //!< Get the base representation of the type
static constexpr int digits10 = USHORT_DIG; //!< Get the number of radix digits unsigned short represents
static constexpr int max_digits10 = USHORT_DECIMAL_DIG; //!< Get the number of decimal digits unsigned short represents
static constexpr int radix = USHORT_RADIX; //!< Get the maximum number of decimal digits unsigned short represents
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; //!< Get the minimum number of decimal digits that represent the exponent of unsigned short
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; //!< 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 max() { return USHORT_MAX; }
static constexpr unsigned short lowest() { return 1; }
static constexpr unsigned short epsilon() { return 1; }
static constexpr unsigned short round_error() { return 0; }
static constexpr unsigned short infinity() { return 0; }
static constexpr unsigned short quiet_NaN() { return 0; }
static constexpr unsigned short signaling_NaN() { return 0; }
static constexpr unsigned short denorm_min() { return 0; }
static constexpr unsigned short min() { return USHORT_MIN; } //!< \returns the minimum finite value of unsigned short
static constexpr unsigned short max() { return USHORT_MAX; } //!< \returns the maximum finite value of unsigned short
static constexpr unsigned short lowest() { return 1; } //!< \returns the smallest positive value of unsigned short
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; } //!< \returns the max rounding error of unsigned short
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; } //!< \returns a value of unsigned short holding a quiet NaN
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; } //!< \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>
{
static constexpr bool is_specialized = true;
static constexpr bool is_signed = true;
static constexpr bool is_integer = true;
static constexpr bool is_exact = true;
static constexpr bool has_infinity = false;
static constexpr bool has_quiet_nan = false;
static constexpr bool has_signaling_nan = false;
static constexpr bool has_denorm = false;
static constexpr bool has_denorm_loss = false;
static constexpr bool is_iec559 = false;
static constexpr bool is_bounded = true;
static constexpr bool is_modulo = true;
static constexpr bool tinyness_before = false;
static constexpr bool traps = true;
static constexpr bool is_specialized = true; //!< Check if the template is specialized for int
static constexpr bool is_signed = true; //!< Check if int is signed
static constexpr bool is_integer = true; //!< Check if int is of an integral type
static constexpr bool is_exact = true; //!< Check if int is exact in its precision
static constexpr bool has_infinity = false; //!< Check if int can hold a value representing infinity
static constexpr bool has_quiet_nan = false; //!< Check if int can hold a non-signaling nan
static constexpr bool has_signaling_nan = false; //!< Check if int can hold a signaling nan
static constexpr bool has_denorm = false; //!< Check if int denormalizes
static constexpr bool has_denorm_loss = false; //!< Check if int has precision loss when denormalized
static constexpr bool is_iec559 = false; //!< Check if int represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; //!< Check if int represents a finite set of values
static constexpr bool is_modulo = true; //!< Check if int can handle modulo arithmetic
static constexpr bool tinyness_before = false; //!< Check if int checks for tinyness before rounding
static constexpr bool traps = true; //!< Check if int can cause operations to trap
static constexpr int digits = INT_RADIX_DIG;
static constexpr int digits10 = INT_DIG;
static constexpr int max_digits10 = INT_DECIMAL_DIG;
static constexpr int radix = INT_RADIX;
static constexpr int min_exponent = 0;
static constexpr int min_exponent10 = 0;
static constexpr int max_exponent = 0;
static constexpr int max_exponent10 = 0;
static constexpr int digits = INT_RADIX_DIG; //!< Get the base representation of the type
static constexpr int digits10 = INT_DIG; //!< Get the number of radix digits int represents
static constexpr int max_digits10 = INT_DECIMAL_DIG; //!< Get the number of decimal digits int represents
static constexpr int radix = INT_RADIX; //!< Get the maximum number of decimal digits int represents
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; //!< Get the minimum number of decimal digits that represent the exponent of int
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; //!< Get the maximum number of decimal digits that represent the exponent of int
static constexpr int min() { return INT_MIN; }
static constexpr int max() { return INT_MAX; }
static constexpr int lowest() { return 1; }
static constexpr int epsilon() { return 1; }
static constexpr int round_error() { return 0; }
static constexpr int infinity() { return 0; }
static constexpr int quiet_NaN() { return 0; }
static constexpr int signaling_NaN() { return 0; }
static constexpr int denorm_min() { return 0; }
static constexpr int min() { return INT_MIN; } //!< \returns the minimum finite value of int
static constexpr int max() { return INT_MAX; } //!< \returns the maximum finite value of int
static constexpr int lowest() { return 1; } //!< \returns the smallest positive value of int
static constexpr int epsilon() { return 1; } //!< \returns the difference between 1.0 and the next representable value
static constexpr int round_error() { return 0; } //!< \returns the max rounding error of int
static constexpr int infinity() { return 0; } //!< \returns a value of int holding a positive infinity
static constexpr int quiet_NaN() { return 0; } //!< \returns a value of int holding a quiet NaN
static constexpr int signaling_NaN() { return 0; } //!< \returns a value of int holding a signaling NaN
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>
{
static constexpr bool is_specialized = true;
static constexpr bool is_signed = false;
static constexpr bool is_integer = true;
static constexpr bool is_exact = true;
static constexpr bool has_infinity = false;
static constexpr bool has_quiet_nan = false;
static constexpr bool has_signaling_nan = false;
static constexpr bool has_denorm = false;
static constexpr bool has_denorm_loss = false;
static constexpr bool is_iec559 = false;
static constexpr bool is_bounded = true;
static constexpr bool is_modulo = true;
static constexpr bool tinyness_before = false;
static constexpr bool traps = true;
static constexpr bool is_specialized = true; //!< Check if the template is specialized for unsigned int
static constexpr bool is_signed = false; //!< Check if unsigned int is signed
static constexpr bool is_integer = true; //!< Check if unsigned int is of an integral type
static constexpr bool is_exact = true; //!< Check if unsigned int is exact in its precision
static constexpr bool has_infinity = false; //!< Check if unsigned int can hold a value representing infinity
static constexpr bool has_quiet_nan = false; //!< Check if unsigned int can hold a non-signaling nan
static constexpr bool has_signaling_nan = false; //!< Check if unsigned int can hold a signaling nan
static constexpr bool has_denorm = false; //!< Check if unsigned int denormalizes
static constexpr bool has_denorm_loss = false; //!< Check if unsigned int has precision loss when denormalized
static constexpr bool is_iec559 = false; //!< Check if unsigned int represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; //!< Check if unsigned int represents a finite set of values
static constexpr bool is_modulo = true; //!< Check if unsigned int can handle modulo arithmetic
static constexpr bool tinyness_before = false; //!< Check if unsigned int checks for tinyness before rounding
static constexpr bool traps = true; //!< Check if unsigned int can cause operations to trap
static constexpr int digits = UINT_RADIX_DIG;
static constexpr int digits10 = UINT_DIG;
static constexpr int max_digits10 = UINT_DECIMAL_DIG;
static constexpr int radix = UINT_RADIX;
static constexpr int min_exponent = 0;
static constexpr int min_exponent10 = 0;
static constexpr int max_exponent = 0;
static constexpr int max_exponent10 = 0;
static constexpr int digits = UINT_RADIX_DIG; //!< Get the base representation of the type
static constexpr int digits10 = UINT_DIG; //!< Get the number of radix digits unsigned int represents
static constexpr int max_digits10 = UINT_DECIMAL_DIG; //!< Get the number of decimal digits unsigned int represents
static constexpr int radix = UINT_RADIX; //!< Get the maximum number of decimal digits unsigned int represents
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; //!< Get the minimum number of decimal digits that represent the exponent of unsigned int
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; //!< 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 max() { return UINT_MAX; }
static constexpr unsigned int lowest() { return 1; }
static constexpr unsigned int epsilon() { return 1; }
static constexpr unsigned int round_error() { return 0; }
static constexpr unsigned int infinity() { return 0; }
static constexpr unsigned int quiet_NaN() { return 0; }
static constexpr unsigned int signaling_NaN() { return 0; }
static constexpr unsigned int denorm_min() { return 0; }
static constexpr unsigned int min() { return UINT_MIN; } //!< \returns the minimum finite value of unsigned int
static constexpr unsigned int max() { return UINT_MAX; } //!< \returns the maximum finite value of unsigned int
static constexpr unsigned int lowest() { return 1; } //!< \returns the smallest positive value of unsigned int
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; } //!< \returns the max rounding error of unsigned int
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; } //!< \returns a value of unsigned int holding a quiet NaN
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; } //!< \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>
{
static constexpr bool is_specialized = true;
static constexpr bool is_signed = true;
static constexpr bool is_integer = true;
static constexpr bool is_exact = true;
static constexpr bool has_infinity = false;
static constexpr bool has_quiet_nan = false;
static constexpr bool has_signaling_nan = false;
static constexpr bool has_denorm = false;
static constexpr bool has_denorm_loss = false;
static constexpr bool is_iec559 = false;
static constexpr bool is_bounded = true;
static constexpr bool is_modulo = true;
static constexpr bool tinyness_before = false;
static constexpr bool traps = true;
static constexpr bool is_specialized = true; //!< Check if the template is specialized for long int
static constexpr bool is_signed = true; //!< Check if long int is signed
static constexpr bool is_integer = true; //!< Check if long int is of an integral type
static constexpr bool is_exact = true; //!< Check if long int is exact in its precision
static constexpr bool has_infinity = false; //!< Check if long int can hold a value representing infinity
static constexpr bool has_quiet_nan = false; //!< Check if long int can hold a non-signaling nan
static constexpr bool has_signaling_nan = false; //!< Check if long int can hold a signaling nan
static constexpr bool has_denorm = false; //!< Check if long int denormalizes
static constexpr bool has_denorm_loss = false; //!< Check if long int has precision loss when denormalized
static constexpr bool is_iec559 = false; //!< Check if long int represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; //!< Check if long int represents a finite set of values
static constexpr bool is_modulo = true; //!< Check if long int can handle modulo arithmetic
static constexpr bool tinyness_before = false; //!< Check if long int checks for tinyness before rounding
static constexpr bool traps = true; //!< Check if long int can cause operations to trap
static constexpr int digits = LONG_RADIX_DIG;
static constexpr int digits10 = LONG_DIG;
static constexpr int max_digits10 = LONG_DECIMAL_DIG;
static constexpr int radix = LONG_RADIX;
static constexpr int min_exponent = 0;
static constexpr int min_exponent10 = 0;
static constexpr int max_exponent = 0;
static constexpr int max_exponent10 = 0;
static constexpr int digits = LONG_RADIX_DIG; //!< Get the base representation of the type
static constexpr int digits10 = LONG_DIG; //!< Get the number of radix digits long int represents
static constexpr int max_digits10 = LONG_DECIMAL_DIG; //!< Get the number of decimal digits long int represents
static constexpr int radix = LONG_RADIX; //!< Get the maximum number of decimal digits long int represents
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; //!< Get the minimum number of decimal digits that represent the exponent of long int
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; //!< 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 max() { return LONG_MAX; }
static constexpr long int lowest() { return 1; }
static constexpr long int epsilon() { return 1; }
static constexpr long int round_error() { return 0; }
static constexpr long int infinity() { return 0; }
static constexpr long int quiet_NaN() { return 0; }
static constexpr long int signaling_NaN() { return 0; }
static constexpr long int denorm_min() { return 0; }
static constexpr long int min() { return LONG_MIN; } //!< \returns the minimum finite value of long int
static constexpr long int max() { return LONG_MAX; } //!< \returns the maximum finite value of long int
static constexpr long int lowest() { return 1; } //!< \returns the smallest positive value of long int
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; } //!< \returns the max rounding error of long int
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; } //!< \returns a value of long int holding a quiet NaN
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; } //!< \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>
{
static constexpr bool is_specialized = true;
static constexpr bool is_signed = false;
static constexpr bool is_integer = true;
static constexpr bool is_exact = true;
static constexpr bool has_infinity = false;
static constexpr bool has_quiet_nan = false;
static constexpr bool has_signaling_nan = false;
static constexpr bool has_denorm = false;
static constexpr bool has_denorm_loss = false;
static constexpr bool is_iec559 = false;
static constexpr bool is_bounded = true;
static constexpr bool is_modulo = true;
static constexpr bool tinyness_before = false;
static constexpr bool traps = true;
static constexpr bool is_specialized = true; //!< Check if the template is specialized for unsigned long int
static constexpr bool is_signed = false; //!< Check if unsigned long int is signed
static constexpr bool is_integer = true; //!< Check if unsigned long int is of an integral type
static constexpr bool is_exact = true; //!< Check if unsigned long int is exact in its precision
static constexpr bool has_infinity = false; //!< Check if unsigned long int can hold a value representing infinity
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; //!< Check if unsigned long int can hold a signaling nan
static constexpr bool has_denorm = false; //!< Check if unsigned long int denormalizes
static constexpr bool has_denorm_loss = false; //!< Check if unsigned long int has precision loss when denormalized
static constexpr bool is_iec559 = false; //!< Check if unsigned long int represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; //!< Check if unsigned long int represents a finite set of values
static constexpr bool is_modulo = true; //!< Check if unsigned long int can handle modulo arithmetic
static constexpr bool tinyness_before = false; //!< Check if unsigned long int checks for tinyness before rounding
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 digits10 = ULONG_DIG;
static constexpr int max_digits10 = ULONG_DECIMAL_DIG;
static constexpr int radix = ULONG_RADIX;
static constexpr int min_exponent = 0;
static constexpr int min_exponent10 = 0;
static constexpr int max_exponent = 0;
static constexpr int max_exponent10 = 0;
static constexpr int digits = ULONG_RADIX_DIG; //!< Get the base representation of the type
static constexpr int digits10 = ULONG_DIG; //!< Get the number of radix digits unsigned long int represents
static constexpr int max_digits10 = ULONG_DECIMAL_DIG; //!< Get the number of decimal digits unsigned long int represents
static constexpr int radix = ULONG_RADIX; //!< Get the maximum number of decimal digits unsigned long int represents
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; //!< Get the minimum number of decimal digits that represent the exponent of unsigned long int
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; //!< 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 max() { return ULONG_MAX; }
static constexpr unsigned long lowest() { return 1; }
static constexpr unsigned long epsilon() { return 1; }
static constexpr unsigned long round_error() { return 0; }
static constexpr unsigned long infinity() { return 0; }
static constexpr unsigned long quiet_NaN() { return 0; }
static constexpr unsigned long signaling_NaN() { return 0; }
static constexpr unsigned long denorm_min() { return 0; }
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; } //!< \returns the maximum finite value of unsigned long int
static constexpr unsigned long lowest() { return 1; } //!< \returns the smallest positive value of unsigned long int
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; } //!< \returns the max rounding error of unsigned long int
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; } //!< \returns a value of unsigned long int holding a quiet NaN
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; } //!< \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>
{
static constexpr bool is_specialized = true;
static constexpr bool is_signed = true;
static constexpr bool is_integer = true;
static constexpr bool is_exact = true;
static constexpr bool has_infinity = false;
static constexpr bool has_quiet_nan = false;
static constexpr bool has_signaling_nan = false;
static constexpr bool has_denorm = false;
static constexpr bool has_denorm_loss = false;
static constexpr bool is_iec559 = false;
static constexpr bool is_bounded = true;
static constexpr bool is_modulo = true;
static constexpr bool tinyness_before = false;
static constexpr bool traps = true;
static constexpr bool is_specialized = true; //!< Check if the template is specialized for long long
static constexpr bool is_signed = true; //!< Check if long long is signed
static constexpr bool is_integer = true; //!< Check if long long is of an integral type
static constexpr bool is_exact = true; //!< Check if long long is exact in its precision
static constexpr bool has_infinity = false; //!< Check if long long can hold a value representing infinity
static constexpr bool has_quiet_nan = false; //!< Check if long long can hold a non-signaling nan
static constexpr bool has_signaling_nan = false; //!< Check if long long can hold a signaling nan
static constexpr bool has_denorm = false; //!< Check if long long denormalizes
static constexpr bool has_denorm_loss = false; //!< Check if long long has precision loss when denormalized
static constexpr bool is_iec559 = false; //!< Check if long long represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; //!< Check if long long represents a finite set of values
static constexpr bool is_modulo = true; //!< Check if long long can handle modulo arithmetic
static constexpr bool tinyness_before = false; //!< Check if long long checks for tinyness before rounding
static constexpr bool traps = true; //!< Check if long long can cause operations to trap
static constexpr int digits = LLONG_RADIX_DIG;
static constexpr int digits10 = LLONG_DIG;
static constexpr int max_digits10 = LLONG_DECIMAL_DIG;
static constexpr int radix = LLONG_RADIX;
static constexpr int min_exponent = 0;
static constexpr int min_exponent10 = 0;
static constexpr int max_exponent = 0;
static constexpr int max_exponent10 = 0;
static constexpr int digits = LLONG_RADIX_DIG; //!< Get the base representation of the type
static constexpr int digits10 = LLONG_DIG; //!< Get the number of radix digits long long represents
static constexpr int max_digits10 = LLONG_DECIMAL_DIG; //!< Get the number of decimal digits long long represents
static constexpr int radix = LLONG_RADIX; //!< Get the maximum number of decimal digits long long represents
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; //!< Get the minimum number of decimal digits that represent the exponent of long long
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; //!< 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 max() { return LLONG_MAX; }
static constexpr long long lowest() { return 1; }
static constexpr long long epsilon() { return 1; }
static constexpr long long round_error() { return 0; }
static constexpr long long infinity() { return 0; }
static constexpr long long quiet_NaN() { return 0; }
static constexpr long long signaling_NaN() { return 0; }
static constexpr long long denorm_min() { return 0; }
static constexpr long long min() { return LLONG_MIN; } //!< \returns the minimum finite value of long long
static constexpr long long max() { return LLONG_MAX; } //!< \returns the maximum finite value of long long
static constexpr long long lowest() { return 1; } //!< \returns the smallest positive value of long long
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; } //!< \returns the max rounding error of long long
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; } //!< \returns a value of long long holding a quiet NaN
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; } //!< \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>
{
static constexpr bool is_specialized = true;
static constexpr bool is_signed = false;
static constexpr bool is_integer = true;
static constexpr bool is_exact = true;
static constexpr bool has_infinity = false;
static constexpr bool has_quiet_nan = false;
static constexpr bool has_signaling_nan = false;
static constexpr bool has_denorm = false;
static constexpr bool has_denorm_loss = false;
static constexpr bool is_iec559 = false;
static constexpr bool is_bounded = true;
static constexpr bool is_modulo = true;
static constexpr bool tinyness_before = false;
static constexpr bool traps = true;
static constexpr bool is_specialized = true; //!< Check if the template is specialized for unsigned long long
static constexpr bool is_signed = false; //!< Check if unsigned long long is signed
static constexpr bool is_integer = true; //!< Check if unsigned long long is of an integral type
static constexpr bool is_exact = true; //!< Check if unsigned long long is exact in its precision
static constexpr bool has_infinity = false; //!< Check if unsigned long long can hold a value representing infinity
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; //!< Check if unsigned long long can hold a signaling nan
static constexpr bool has_denorm = false; //!< Check if unsigned long long denormalizes
static constexpr bool has_denorm_loss = false; //!< Check if unsigned long long has precision loss when denormalized
static constexpr bool is_iec559 = false; //!< Check if unsigned long long represents an IEC 559 or IEEE 754
static constexpr bool is_bounded = true; //!< Check if unsigned long long represents a finite set of values
static constexpr bool is_modulo = true; //!< Check if unsigned long long can handle modulo arithmetic
static constexpr bool tinyness_before = false; //!< Check if unsigned long long checks for tinyness before rounding
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 digits10 = ULLONG_DIG;
static constexpr int max_digits10 = ULLONG_DECIMAL_DIG;
static constexpr int radix = ULLONG_RADIX;
static constexpr int min_exponent = 0;
static constexpr int min_exponent10 = 0;
static constexpr int max_exponent = 0;
static constexpr int max_exponent10 = 0;
static constexpr int digits = ULLONG_RADIX_DIG; //!< Get the base representation of the type
static constexpr int digits10 = ULLONG_DIG; //!< Get the number of radix digits unsigned long long represents
static constexpr int max_digits10 = ULLONG_DECIMAL_DIG; //!< Get the number of decimal digits unsigned long long represents
static constexpr int radix = ULLONG_RADIX; //!< Get the maximum number of decimal digits unsigned long long represents
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; //!< Get the minimum number of decimal digits that represent the exponent of unsigned long long
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; //!< 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 max() { return ULLONG_MAX; }
static constexpr unsigned long long lowest() { return 1; }
static constexpr unsigned long long epsilon() { return 1; }
static constexpr unsigned long long round_error() { return 0; }
static constexpr unsigned long long infinity() { return 0; }
static constexpr unsigned long long quiet_NaN() { return 0; }
static constexpr unsigned long long signaling_NaN() { return 0; }
static constexpr unsigned long long denorm_min() { return 0; }
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; } //!< \returns the maximum finite value of unsigned long long
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; } //!< \returns the difference between 1.0 and the next representable value
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; } //!< \returns a value of unsigned long long holding a positive infinity
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; } //!< \returns a value of unsigned long long holding a signaling NaN
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
///
/// \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.
/// \code{cpp}
/// 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
/// \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
/// \tparam T type of the values, must satisfy `fennec::is_integral<T>`

View File

@@ -32,12 +32,13 @@
#define FENNEC_LANG_RANGES_H
#include <fennec/lang/types.h>
#include <fennec/lang/type_traits.h>
namespace fennec
{
///
/// \brief C++ Iterator Specification \f$begin()\f$
/// \brief C++ Iterator Specification \emph{begin()}
/// \tparam ContainerT the container type
/// \param c the container to iterate on
/// \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
/// \param c the container to iterate on
/// \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 N the bounds of the array
/// \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
/// \param c the container to iterate on
/// \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
/// \param c the container to iterate on
/// \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 N the bounds of the array
/// \param arr a bounded array to iterate on
@@ -99,6 +100,129 @@ inline constexpr T* end(T (&arr)[N]) noexcept {
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

View File

@@ -1,6 +1,6 @@
// =====================================================================================================================
// 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
// 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/>.
// =====================================================================================================================
#ifndef FENNEC_CORE_SYSTEM_H
#define FENNEC_CORE_SYSTEM_H
#include <fennec/string/string.h>
///
/// \file system.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
{
class system {
public:
using tick_f = void (*)(system*, double);
using frame_f = void (*)(system*, size_t);
const string name;
const tick_f tick;
const frame_f frame;
system(const cstring& name, tick_f tick, frame_f frame)
: name(name), tick(tick), frame(frame) {
}
virtual ~system() = default;
virtual void init() = 0;
virtual void shutdown() = 0;
};
using ::system;
}
#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 =======================================================================================
///
/// \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 { };
#ifndef FENNEC_DOXYGEN
@@ -134,7 +134,7 @@ template<typename...Ts> constexpr size_t max_element_size_v = max_element_size<T
// 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 Ts The type sequence to check
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 ============================================================================================
///
/// \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 Ts The type sequence to check
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
/// \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 {
if consteval {
return true;
@@ -461,7 +461,7 @@ template<typename T> struct is_void
: detail::_is_void<remove_cvref_t<T>>{};
///
/// \brief Shorthand for ```is_void<T>::value```
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
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>>{};
///
/// \brief Shorthand for ```is_null_pointer<T>::value```
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
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>>{};
///
/// \brief Shorthand for ```is_bool<T>::value```
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
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>> {};
///
/// \brief Shorthand for ```is_integral<T>::value```
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
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>>{};
///
/// \brief Shorthand for ```is_floating_point<T>::value```
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
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
///
/// \brief Shorthand for ```is_array<T>::value```
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
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>>{};
///
/// \brief Shorthand for ```is_pointer<T>::value```
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
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
///
/// \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
template<typename T> struct is_lvalue_reference
: detail::_is_lvalue_reference<T>{};
///
/// \brief Shorthand for ```is_floating_point<T>::value```
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
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
///
/// \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
template<typename T> struct is_rvalue_reference
: detail::_is_rvalue_reference<T>{};
///
/// \brief Shorthand for ```is_floating_point<T>::value```
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
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
///
/// \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
template<typename T> struct is_member_function_pointer
: 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
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
///
/// \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
template<typename T> struct is_member_object_pointer
: 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
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
///
/// \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
template<typename T> struct is_arithmetic
: bool_constant<is_integral_v<T> or is_floating_point_v<T>>{};
///
/// \brief Shorthand for ```is_arithmetic<T>::value```
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
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>>{};
///
/// \brief Shorthand for ```is_fundamental<T>::value```
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
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
///
/// \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
template<typename T> struct is_scalar
: bool_constant<is_arithmetic_v<T> or is_enum_v<T> or is_pointer_v<T>>{};
///
/// \brief Shorthand for ```is_scalar<T>::value```
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
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
///
/// \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
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
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
///
/// \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
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
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
///
/// \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
template<typename T> struct is_reference
: detail::_is_reference<T>{};
///
/// \brief Shorthand for ```is_reference<T>::value```
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
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
///
/// \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
template<typename T> struct is_member_pointer
: 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
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
///
/// \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
template<typename T> struct is_const
: detail::_is_const<T>{};
///
/// \brief Shorthand for ```is_const<T>::value```
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
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
///
/// \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
template<typename T> struct is_volatile
: detail::_is_volatile<T>{};
///
/// \brief Shorthand for ```is_volatile<T>::value```
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
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 --------------------------------------------------------------------------------------------------
///
/// \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
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 ---------------------------------------------------------------------------------------
///
/// \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
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 ------------------------------------------------------------------------------------------
///
/// \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
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 ---------------------------------------------------------------------------
///
/// \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
template<typename T> struct has_unique_object_representations
: 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 ----------------------------------------------------------------------------------------------------
///
/// \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
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 ----------------------------------------------------------------------------------------------
///
/// \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
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 -------------------------------------------------------------------------------------------------
///
/// \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
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 -------------------------------------------------------------------------------------------------
///
/// \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
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 -------------------------------------------------------------------------------------------------
///
/// \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
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 -------------------------------------------------------------------------------------------------
///
/// \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
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
///
/// \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
template<typename T> struct is_signed
: detail::_is_signed<remove_cvref_t<T>> {};
///
/// \brief Shorthand for ```is_signed<T>::value```
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
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
///
/// \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
template<typename T> struct is_unsigned
: detail::_is_unsigned<remove_cvref_t<T>> {};
///
/// \brief Shorthand for ```is_unsigned<T>::value```
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
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 --------------------------------------------------------------------------------------------
#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
/// \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]>
: true_type {};
#endif
///
/// \brief Shorthand for ```is_bounded_array<T>::value```
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
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 ------------------------------------------------------------------------------------------
#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
/// \tparam T type to check
@@ -1123,10 +1101,8 @@ template<typename T> struct is_unbounded_array
template<typename T> struct is_unbounded_array<T[]>
: true_type {};
#endif
///
/// \brief Shorthand for ```is_unbounded_array<T>::value```
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
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
///
/// \brief Shorthand for ```is_scoped_enum<T>::value```
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
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 ----------------------------------------------------------------------------------------------
///
/// \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 ToT Second type
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 --------------------------------------------------------------------------------------------
///
/// \brief Check if \f$ClassT\f$ can be constructed with `ArgsT,` i.e. `ClassT(ArgsT...)`.
/// This may be read as "is \f$ClassT\f$ constructible with \f$ArgsT\f$"
/// \brief Check if \emph{ClassT} can be constructed with \emph{ArgsT...}, i.e. `ClassT(ArgsT...)`.
/// This may be read as "is \emph{ClassT} constructible with \emph{ArgsT}"
/// \tparam ClassT The class type to test
/// \tparam ArgsT The arguments for the specific constructor
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 ----------------------------------------------------------------------------------
///
/// \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 ArgsT The arguments for the specific constructor
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 ------------------------------------------------------------------------------------
///
/// \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 ArgsT The arguments for the specific constructor
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 ------------------------------------------------------------------------------------
///
/// \brief Check if \f$ClassT\f$ is default constructible
/// \brief Check if \emph{ClassT} is default constructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_default_constructible
: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT)> {};
@@ -1256,7 +1232,7 @@ template<typename ClassT> constexpr bool_t is_default_constructible_v = is_defau
// 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
template<typename ClassT> struct is_trivially_default_constructible
: 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 --------------------------------------------------------------------------
///
/// \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
template<typename ClassT> struct is_nothrow_default_constructible
: 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 ---------------------------------------------------------------------------------------
///
/// \brief Check if \f$ClassT\f$ is copy constructible
/// \brief Check if \emph{ClassT} is copy constructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_copy_constructible
: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {};
@@ -1298,7 +1274,7 @@ template<typename ClassT, typename...ArgsT> constexpr bool_t is_copy_constructib
// 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
template<typename ClassT> struct is_trivially_copy_constructible
: 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 -------------------------------------------------------------------------------
///
/// \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
template<typename ClassT> struct is_nothrow_copy_constructible
: 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 ---------------------------------------------------------------------------------------
///
/// \brief Check if \f$ClassT\f$ is move constructible
/// \brief Check if \emph{ClassT} is move constructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_move_constructible
: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_rvalue_reference_t<ClassT>)> {};
@@ -1340,7 +1316,7 @@ template<typename ClassT, typename...ArgsT> constexpr bool_t is_move_constructib
// 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
template<typename ClassT> struct is_trivially_move_constructible
: 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 -------------------------------------------------------------------------------
///
/// \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
template<typename ClassT> struct is_nothrow_move_constructible
: 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 -----------------------------------------------------------------------------------------------
///
/// \brief Check if \f$ClassT\f$ is assignable
/// \brief Check if \emph{ClassT} is assignable
/// \tparam ClassAT The class type to test
/// \tparam ClassBT The arguments for the specific constructor
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 -------------------------------------------------------------------------------------
///
/// \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 ClassBT The arguments for the specific constructor
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 ---------------------------------------------------------------------------------------
///
/// \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 ClassBT The arguments for the specific constructor
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 ------------------------------------------------------------------------------------------
///
/// \brief Check if \f$ClassT\f$ is copy assignable
/// \brief Check if \emph{ClassT} is copy assignable
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_copy_assignable
: bool_constant<FENNEC_BUILTIN_IS_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_lvalue_reference_t<const ClassT>)> {};
@@ -1428,7 +1404,7 @@ template<typename ClassT> constexpr bool_t is_copy_assignable_v = is_copy_assign
// 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
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>)> {};
@@ -1442,7 +1418,7 @@ template<typename ClassT> constexpr bool_t is_trivially_copy_assignable_v = is_t
// 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
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>)> {};
@@ -1456,7 +1432,7 @@ template<typename ClassT> constexpr bool_t is_nothrow_copy_assignable_v = is_not
// 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
template<typename ClassT> struct is_move_assignable
: 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 --------------------------------------------------------------------------------
///
/// \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
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>)> {};
@@ -1484,7 +1460,7 @@ template<typename ClassT> constexpr bool_t is_trivially_move_assignable_v = is_t
// 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
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>)> {};
@@ -1498,7 +1474,7 @@ template<typename ClassT> constexpr bool_t is_nothrow_move_assignable_v = is_not
// 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
template<typename ClassT> struct is_destructible
: 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 -----------------------------------------------------------------------------------
///
/// \brief Check if \f$ClassT\f$ is trivially destructible
/// \brief Check if \emph{ClassT} is trivially destructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_trivially_destructible
#if FENNEC_HAS_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE
: 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`
@@ -1526,7 +1506,7 @@ template<typename ClassT> constexpr bool_t is_trivially_destructible_v = is_triv
// 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
template<typename ClassT> struct is_nothrow_destructible
: 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
///
/// \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 T1 second type to check
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 {};
///
/// \brief Shorthand for ```is_same<T0, T1>::value```
/// \brief Shorthand for `(.*?)`
/// \tparam T0 first type to check
/// \tparam T1 second type to check
template<typename T0, typename T1> constexpr bool_t is_same_v = is_same<T0, T1> {};
@@ -1566,9 +1546,9 @@ template<typename T0, typename T1> constexpr bool_t is_same_v = is_same<T0, T1>
// 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 Derived derived type to check
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 Derived derived type to check
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 -------------------------------------------------------------------------------------------------
///
/// \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
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 ------------------------------------------------------------------------------------------------
///
/// \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
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 -------------------------------------------------------------------------------------------------
///
/// \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
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 =================================================================================================
///
/// \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
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
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
template<typename T> struct strip_pointers : conditional_t<
detail::_is_pointer<T>::value,
@@ -237,9 +237,9 @@ template<typename T> using strip_pointers_t = strip_pointers<T>::type;
// 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
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
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
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
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 ========================================================================================
///
/// \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
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
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
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
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$
/// become \f$const volatile T\f$
/// \details removes references from the provided type such that \emph{T}, \emph{const\quad T}, and \emph{volatile\quad T}
/// become \emph{const volatile T}
/// \tparam T Reference Type
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
/// \f$const\quad volatile\quad T\f$ become \f$T\f$
/// \details removes const and volatile from the provided type such that \emph{const\quad T}, \emph{volatile\quad T}, and
/// \emph{const\quad volatile\quad T} become \emph{T}
/// \tparam T Reference Type
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.
/// \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
/// \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
/// \tparam T Reference Type

View File

@@ -84,10 +84,10 @@ template<typename T> constexpr T&& forward(remove_reference_t<T>&& x) noexcept {
#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
/// \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) {
return fennec::forward<T>(v);
}

View File

@@ -295,11 +295,11 @@ namespace fennec
// 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>
/// \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
template<typename genType>
@@ -311,11 +311,11 @@ constexpr genType sign(genType x) {
// 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>
/// \f$\text{abs}(x)=\left|x\right|\f$.<br> <br>
/// \math{\text{abs}(x)=\left|x\right|}.<br> <br>
///
/// \param x input value
template<typename genType>
@@ -337,11 +337,11 @@ constexpr genType abs(genType x) {
// 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>
/// \f$\text{floor}(x)=\lfloor x\rfloor\f$<br> <br>
/// \math{\text{floor}(x)=\lfloor x\rfloor}<br> <br>
///
/// \param x input value
template<typename genType>
@@ -354,11 +354,11 @@ constexpr genType floor(genType x) {
// 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>
/// \f$\text{ceil}(x)=\lceil{x}\rceil\f$ <br> <br>
/// \math{\text{ceil}(x)=\lceil{x}\rceil} <br> <br>
///
/// \param x input value
template<typename genType>
@@ -371,12 +371,12 @@ constexpr genType ceil(genType x) {
// 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>
/// \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>
/// \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
template<typename genType> constexpr genType round(genType x) {
@@ -388,11 +388,11 @@ template<typename genType> constexpr genType round(genType x) {
// 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>
/// \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
template<typename genType>
@@ -405,13 +405,13 @@ constexpr genType trunc(genType x) {
// 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.
///
/// \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>
/// \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
template<typename genType>
@@ -451,11 +451,11 @@ constexpr genType roundEven(genType x) {
// 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>
/// \f$\text{fract}(x)=x-\text{floor}\f$<br> <br>
/// \math{\text{fract}(x)=x-\text{floor}}<br> <br>
///
/// \param x input value
template<typename genType>
@@ -467,11 +467,11 @@ constexpr genType fract(genType x) {
// 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>
/// \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 y divisor
@@ -484,11 +484,11 @@ constexpr genType mod(genType x, genType y) {
// 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>
/// \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 i integral out
@@ -501,14 +501,14 @@ constexpr genType modf(genType x, genType& i) {
// 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>
/// \details \f$NaN\f$ is a concept unique to computing. It strictly means, and more specifically,
/// \returns **true** if \math{x} holds a NaN. Returns **false** otherwise. <br> <br>
/// \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,
/// like \ref fennec::sqrt "sqrt()", return \f$NaN\f$ when an expression would return
/// a value in a different coordinate space. There are other cases, such as \f$\frac{1}{x}\f$,
/// where \f$x=0\f$ is undefined, and respectively the return value is also \f$NaN\f$. <br> <br>
/// 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 \math{\frac{1}{x}},
/// 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>
///
@@ -522,10 +522,10 @@ constexpr genBType isnan(genType x) {
// 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.
/// \details \f$\inf\f$, or \f$\infty\f$, is used to express any function that is boundless, endless, or larger
/// \returns **true** if \math{x} holds a positive or negative infinity. Returns **false** otherwise.
/// \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>
///
/// \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.
/// The float value's bit-level representation is preserved. <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 \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 \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 \f$s_B=\begin{cases}-1,&b_{31}=1 \\ 1\end{cases}\f$<br> <br>
/// then, \f$x_B=s_B m_B 2^{p_B}\f$<br>
/// and, \f$i_B=-b_{31} 2^{31}+\sum_{i=0}^{30}{a_i 2^i}\f$<br>
/// and, \f$u_B=\sum_{i=0}^{31}{a_i 2^i}\f$<br> <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 \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 \math{p_B=b_{23}\cdot 2^0+\cdots +b_i\cdot 2^{i-23}+\cdots +b_{30}\cdot 2^7-127}<br>
/// let \math{s_B=\begin{cases}-1,&b_{31}=1 \\ 1\end{cases}}<br> <br>
/// then, \math{x_B=s_B m_B 2^{p_B}}<br>
/// and, \math{i_B=-b_{31} 2^{31}+\sum_{i=0}^{30}{a_i 2^i}}<br>
/// and, \math{u_B=\sum_{i=0}^{31}{a_i 2^i}}<br> <br>
///
/// \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))
@@ -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>
/// \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 \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 \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 \f$s_B=\begin{cases}-1,&b_{31}=1 \\ 1\end{cases}\f$<br> <br>
/// then, \f$x_B=s_B m_B 2^{p_B}\f$<br>
/// and, \f$i_B=-b_{31} 2^31+\sum_{i=0}^{30}{a_i 2^i}\f$<br>
/// and, \f$u_B=\sum_{i=0}^{31}{a_i 2^i}\f$<br> <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 \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 \math{p_B=b_{23}\cdot 2^0+\cdots +b_i\cdot 2^{i-23}+\cdots +b_{30}\cdot 2^7-127}<br>
/// let \math{s_B=\begin{cases}-1,&b_{31}=1 \\ 1\end{cases}}<br> <br>
/// then, \math{x_B=s_B m_B 2^{p_B}}<br>
/// and, \math{i_B=-b_{31} 2^31+\sum_{i=0}^{30}{a_i 2^i}}<br>
/// and, \math{u_B=\sum_{i=0}^{31}{a_i 2^i}}<br> <br>
///
/// \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))
@@ -600,9 +600,9 @@ constexpr genType uintBitsToFloat(genUType x) {
// 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),
/// 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 ===============================================================================================================
///
/// \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,
/// such that \f$x=sig \cdot 2^{exp}\f$.
/// \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 \math{x=sig \cdot 2^{exp}}.
///
/// \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
/// 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
/// \f$x\f$ 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>
/// \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 \math{exp} are vectors with the same number of components as \math{x}. <br> <br>
///
/// \param x The floating-point value to split
/// \param exp The variable to store the exponent in
@@ -642,11 +642,11 @@ constexpr genType frexp(genType x, genIType& exp) {
// 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,
/// 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),
/// 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
@@ -676,14 +676,14 @@ constexpr genType ldexp(genType x, genIType exp) {
// 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>
/// \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 y input value \f$y\f$
/// \param x input value \math{x}
/// \param y input value \math{y}
template<typename genType>
constexpr genType min(genType x, genType y) {
return (y < x) ? y : x;
@@ -693,11 +693,11 @@ constexpr genType min(genType x, genType y) {
// 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>
/// \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 y second input value
@@ -710,11 +710,11 @@ constexpr genType max(genType x, genType y) {
// 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>
/// \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 minVal minimum value
@@ -738,13 +738,13 @@ constexpr genType clamp(genType x, genType minVal, genType maxVal) {
// 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>
/// \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
template<typename genType> requires(is_floating_point_v<genType>)
constexpr genType step(genType edge, genType x) {
@@ -755,11 +755,11 @@ constexpr genType step(genType edge, genType x) {
// 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
/// interpolation between \f$0\f$ and \f$1\f$ when \f$edge0<x<edge1\f$.
/// \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 \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
/// interpolation between \f$0\f$ and \f$1\f$ when \f$edge0<x<edge1\f$. <br> <br>
/// \returns \math{0.0} if \math{x\le edge0} and \math{1.0} if \math{x\ge edge1}, and performs smooth Hermite
/// 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>
/// This is equivalent to: <br> <br>
/// \code{.glsl}
@@ -767,13 +767,13 @@ constexpr genType step(genType edge, genType x) {
/// t = clamp((x - edge0) / (edge1 - edge0), 0, 1);
/// return t * t * (3 - 2 * t);
/// \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>
/// \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 edge1 \f$x\f$ value where the function returns \f$1.0\f$
/// \param x \f$x\f$ coordinate input
/// \param edge0 \math{x} value where the function returns \math{0.0}
/// \param edge1 \math{x} value where the function returns \math{1.0}
/// \param x \math{x} coordinate input
template<typename genType> requires(is_floating_point_v<genType>)
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);
@@ -783,13 +783,13 @@ constexpr genType smoothstep(genType edge0, genType edge1, genType x) {
// 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>
/// \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
/// 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.
///
/// \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.
///
/// \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,
/// it selects the vector, otherwise, each component is selected. <br> <br>
/// This implementation uses the ternary operator:<br>
/// \code{.cpp}return a ? x : y;\endcode
/// Which will get reduced down to a conditional move instruction over branching.<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 y False Value

View File

@@ -19,10 +19,37 @@
#ifndef 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")
#undef __cplusplus
// Include math.h
#include <math.h>
// Restore __cpluscplus definition and macro redefinition warning
#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 acos

View File

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

View File

@@ -546,148 +546,148 @@ namespace fennec
// Rational Constants ==================================================================================================
template<typename genType> constexpr genType zero() { return genType(0); } //!< \returns The value of \f$0\f$
template<typename genType> constexpr genType one() { return genType(1); } //!< \returns The value of \f$1\f$
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 three_over_two() { return genType(1.5); } //!< \returns The value of \f$\frac{3}{2}\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 \math{1}
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 \math{\frac{3}{2}}
// 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 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 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_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_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_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_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 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_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_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 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 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 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 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 \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 \math{\sqrt{2}} with the highest precision for \emph{genType}
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 \math{\sqrt{5}} with the highest precision for \emph{genType}
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 \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 \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 \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 \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 \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 \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 \math{{2}^{\sqrt{2}}} with the highest precision for \emph{genType}
// Pi ==================================================================================================================
// 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 tau() { return 6.28318530717958647692528676655900576839433879875021; } //!< \returns The value of \f$\tau\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 \math{\tau} with the highest precision for \emph{genType}
// 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 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 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 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 \math{3\pi} with the highest precision for \emph{genType}
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
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 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 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 \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 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 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 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 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 \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 \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 \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 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 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 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 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 \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 \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 \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 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 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 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 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 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 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 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 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 \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 \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 \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 \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 \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 \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 \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 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 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 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 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 \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 \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 \math{\frac{11\pi}{6}} with the highest precision for \emph{genType}
// 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 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 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 \math{\frac{2}{\pi}} with the highest precision for \emph{genType}
// 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_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 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 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 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 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 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 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 \math{{\pi}^{2}} with the highest precision for \emph{genType}
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 \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 \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 \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 \math{\sqrt[3]{\pi}} with the highest precision for \emph{genType}
// e ===================================================================================================================
// 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 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 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 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 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 \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 \math{2e} with the highest precision for \emph{genType}
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
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_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 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 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 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_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_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_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 \math{e^3} with the highest precision for \emph{genType}
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 \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 \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 \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 \math{e^-e} with the highest precision for \emph{genType}
// 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_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_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_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_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 \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 \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 \math{{e}^{\frac{-\pi}{2}}} with the highest precision for \emph{genType}
// 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_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_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 \math{{e}^{-\gamma}} with the highest precision for \emph{genType}
// 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 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 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 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 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 \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 \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 \math{\frac{\pi}{G}} with the highest precision for \emph{genType}
// 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 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 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 \math{\frac{1}{\gamma}} with the highest precision for \emph{genType}
// 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_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_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_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_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 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 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_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_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_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_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_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_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 \math{\log{3}} with the highest precision for \emph{genType}
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 \math{\log{7}} with the highest precision for \emph{genType}
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 \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 \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 \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 \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 \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 \math{\log{\gamma}} with the highest precision for \emph{genType}
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
/// \param q The Quaternion
/// \returns The Hamilton Tensor of \f$q\f$
/// \returns The Hamilton Tensor of \emph{q}
template<typename genType>
constexpr genType norm(const qua<genType>& q) {
return fennec::sqrt(sqnorm(q));
@@ -61,7 +61,7 @@ constexpr genType norm(const qua<genType>& q) {
///
/// \brief Unit Function (Versor)
/// \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>
constexpr qua<genType> unit(const qua<genType>& q) {
genType n = fennec::norm(q);
@@ -71,7 +71,7 @@ constexpr qua<genType> unit(const qua<genType>& q) {
///
/// \brief Reciprocal Function
/// \param q The Quaternion
/// \returns The quaternion \f${q}^{-1}\f$
/// \returns The quaternion \math{\textbf{q}^{-1}}
template<typename genType>
constexpr qua<genType> reciprocal(const qua<genType>& q) {
return ~q / fennec::sqnorm(q);
@@ -99,7 +99,7 @@ public:
// 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() {
data = { 0, 0, 0, 1 };
}
@@ -107,9 +107,9 @@ public:
///
/// \brief Component Constructor
/// \param w The scalar component
/// \param x The coefficient of the \f$i\f$ component
/// \param y The coefficient of the \f$j\f$ component
/// \param z The coefficient of the \f$k\f$ component
/// \param x The coefficient of the \emph{i} component
/// \param y The coefficient of the \emph{j} component
/// \param z The coefficient of the \emph{k} component
constexpr quaternion(scalar_t w, scalar_t x, scalar_t y, scalar_t z) {
data = { x, y, z, w };
}
@@ -160,7 +160,7 @@ public:
///
/// \brief Copy Assignment Operator
/// \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) {
data = q.data;
return *this;
@@ -169,7 +169,7 @@ public:
///
/// \brief Move Assignment Operator
/// \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 {
data = q.data;
return *this;
@@ -182,7 +182,7 @@ public:
/// \brief Equality Operator
/// \param lhs the left 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) {
return lhs.data == rhs.data;
}
@@ -191,7 +191,7 @@ public:
/// \brief Inequality Operator
/// \param lhs the left 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) {
return lhs.data != rhs.data;
}
@@ -202,7 +202,7 @@ public:
///
/// \brief Unary Negation Operator
/// \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) {
return quat_t(-rhs.w, -rhs.x, -rhs.y, -rhs.z);
}
@@ -210,7 +210,7 @@ public:
///
/// \brief Unary Conjugation Operator
/// \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) {
return quat_t(rhs.w, -rhs.x, -rhs.y, -rhs.z);
}
@@ -222,7 +222,7 @@ public:
/// \brief Quaternion-Scalar Multiplication Operator
/// \param lhs The quaternion
/// \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) {
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
/// \param lhs The scalar
/// \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) {
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
/// \param lhs The quaternion
/// \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) {
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
/// \param lhs The scalar
/// \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) {
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
/// \param lhs The quaternion
/// \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) {
lhs.x *= rhs;
lhs.y *= rhs;
@@ -274,7 +274,7 @@ public:
/// \brief Quaternion-Scalar Division Assignment Operator
/// \param lhs The quaternion
/// \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) {
lhs.x /= rhs;
lhs.y /= rhs;
@@ -290,7 +290,7 @@ public:
/// \brief Quaternion-Vector Multiplication Operator
/// \param q the quaternion
/// \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) {
const vec3_t u = q.xyz;
const vec3_t uv = fennec::cross(u, v);
@@ -302,7 +302,7 @@ public:
/// \brief Vector-Quaternion Multiplication Operator
/// \param v the vector
/// \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) {
return fennec::reciprocal(q) * v;
}
@@ -311,7 +311,7 @@ public:
/// \brief Quaternion-Vector Multiplication Operator
/// \param q the quaternion
/// \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) {
return vec4_t(q * v.xyz, v.w);
}
@@ -320,7 +320,7 @@ public:
/// \brief Vector-Quaternion Multiplication Operator
/// \param v the vector
/// \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) {
return fennec::reciprocal(q) * v;
}
@@ -332,7 +332,7 @@ public:
/// \brief Quaternion-Quaternion Addition Operator
/// \param lhs the left 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) {
return quat_t(
lhs.w + rhs.w,
@@ -346,7 +346,7 @@ public:
/// \brief Quaternion-Quaternion Subtraction Operator
/// \param lhs the left 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) {
return quat_t(
lhs.w - rhs.w,
@@ -360,7 +360,7 @@ public:
/// \brief Quaternion-Quaternion Multiplication Operator
/// \param lhs the left 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) {
return quat_t(
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
/// \param lhs the left 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) {
lhs.w += rhs.w;
lhs.x += rhs.x;
@@ -390,7 +390,7 @@ public:
/// \brief Quaternion-Quaternion Subtraction Assignment Operator
/// \param lhs the left 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) {
lhs.w -= rhs.w;
lhs.x -= rhs.x;
@@ -403,7 +403,7 @@ public:
/// \brief Quaternion-Quaternion Multiplication Assignment Operator
/// \param lhs the left 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) {
return lhs = lhs * rhs;
}

View File

@@ -118,14 +118,14 @@ namespace fennec
// dot -----------------------------------------------------------------------------------------------------------------
///
/// \brief Returns the dot product of \f$x\f$ and \f$y\f$, i.e., \f$x_0 \cdot y_0 + x_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>
/// let \f$X=\left[\begin{array}\\ x_0 \\ x_1 \\ \vdots \\ x_N \end{array}\right]\f$ <br>
/// let \f$Y=\left[\begin{array}\\ y_0 \\ y_1 \\ \vdots \\ y_N \end{array}\right]\f$ <br><br>
/// let \math{X=\left[\begin{array}\\ x_0 \\ x_1 \\ \vdots \\ x_N \end{array}\right]} <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 y second vector
@@ -138,13 +138,13 @@ constexpr genType dot(const vector<genType, i...>& x, const vector<genType, i...
// 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>
/// 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
template<typename genType, size_t...i>
@@ -156,13 +156,13 @@ constexpr genType length2(const vector<genType, i...>& x) {
// 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>
/// 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
template<typename genType, size_t...i>
@@ -174,14 +174,14 @@ constexpr genType length(const vector<genType, i...>& x) {
// 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>
/// let \f$X=\left[\begin{array}\\ x_0 \\ x_1 \\ \vdots \\ x_N \end{array}\right]\f$ <br>
/// let \f$Y=\left[\begin{array}\\ y_0 \\ y_1 \\ \vdots \\ y_N \end{array}\right]\f$ <br><br>
/// let \math{X=\left[\begin{array}\\ x_0 \\ x_1 \\ \vdots \\ x_N \end{array}\right]} <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 p1 second vector
@@ -194,16 +194,16 @@ constexpr genType distance(const vector<genType, i...>& p0, const vector<genType
// cross ---------------------------------------------------------------------------------------------------------------
///
/// \brief Returns the cross product of \f$x\f$ and \f$y\f$, 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$
/// \brief Returns the cross product of \math{x} and \math{y}, i.e.,
/// \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.,
/// \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>
/// \returns the cross product of \math{x} and \math{y}, i.e.,
/// \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>
/// let \f$X=\left[\begin{array}\\ x_0 \\ x_1 \\ \vdots \\ x_N \end{array}\right]\f$ <br>
/// let \f$Y=\left[\begin{array}\\ y_0 \\ y_1 \\ \vdots \\ y_N \end{array}\right]\f$ <br><br>
/// let \math{X=\left[\begin{array}\\ x_0 \\ x_1 \\ \vdots \\ x_N \end{array}\right]} <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 y second vector
@@ -216,13 +216,13 @@ constexpr vector<genType, i...> cross(const vector<genType, i...>& x, const vect
// 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>
/// 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
template<typename genType, size_t...i>
@@ -234,9 +234,9 @@ constexpr vector<genType, i...> normalize(const vector<genType, i...>& x) {
// 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 I the incident
@@ -250,11 +250,11 @@ constexpr vector<genType, i...> faceforward(const vector<genType, i...>& N, cons
// 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>
/// \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 N the surface orientation
@@ -266,13 +266,13 @@ constexpr vector<genType, i...> reflect(const vector<genType, i...>& I, const ve
// 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.
///
/// \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>
/// let \f$k=1.0-eta^2 \cdot (1.0 - \text{dot}(N, I)^2)\f$ <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>
/// let \math{k=1.0-eta^2 \cdot (1.0 - \text{dot}(N, I)^2)} <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 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 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>
constexpr vec<scalar, rows> column(const matrix<scalar, rows, cols...>& m, size_t i) noexcept {
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 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>
constexpr vec<scalar, sizeof...(cols)> row(const matrix<scalar, rows, cols...>& m, size_t i) noexcept {
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>
/// Note: to get linear algebraic matrix multiplication, use
/// 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
/// with one column) and the second parameter \f$r\f$ as a row
/// \details Treats the first parameter \emph{c} as a column vector (matrix
/// with one column) and the second parameter \emph{r} as a row
/// vector (matrix with one row) and does a linear algebraic
/// matrix multiply \f$c \cross r\f$, yielding a matrix whose number of
/// rows is the number of components in \f$c\f$ and whose
/// number of columns is the number of components in \f$r\f$.
/// matrix multiply \emph{c \cross r}, yielding a matrix whose number of
/// rows is the number of components in \emph{c} and whose
/// number of columns is the number of components in \emph{r}.
/// \param c the column vector
/// \param r the row vector
/// \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
/// \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.
template<typename scalar, size_t rows, size_t...cols>
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.
template<typename scalar, size_t rows, size_t...cols>
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$.
/// \returns \f$m^{-1}\f$
/// \brief Returns the determinant of \emph{m}.
/// \returns \math{\textbf{m}^{-1}}
template<typename scalar, size_t rows, size_t...cols>
constexpr matrix<scalar, rows, cols...> inverse(const matrix<scalar, rows, cols...>&) noexcept {
static_assert(false, "implementation undefined");
@@ -295,7 +295,7 @@ struct matrix
/// \brief scalar constructor, initializes a diagonal matrix with a scale of \p s
///
/// \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>
/// <caption id="fennec_table_matrix_diagonal"></caption>
/// <tr><th> <th> 0 <th> 1 <th> 2
@@ -359,17 +359,17 @@ struct matrix
///
/// \details
/// \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) {
return data[i];
}
///
/// \brief returns the column at index \f$i\f$
/// \brief returns the column at index \emph{i}
///
/// \details
/// \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 {
return data[i];
}
@@ -378,7 +378,7 @@ struct matrix
/// \details
/// \param i the column
/// \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) {
return data[i][j];
}
@@ -389,7 +389,7 @@ struct matrix
/// \details
/// \param i the column
/// \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 {
return data[i][j];
}
@@ -610,7 +610,7 @@ struct matrix
/// \brief performs a linear algebraic multiply
/// \param lhs the matrix
/// \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) {
return _mul(lhs, rhs);
}
@@ -619,7 +619,7 @@ struct matrix
/// \brief performs a linear algebraic multiply
/// \param lhs the vector
/// \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) {
return row_t(fennec::dot(fennec::column(rhs, ColIndicesV), lhs) ...);
}
@@ -637,7 +637,7 @@ struct matrix
/// \brief matrix comparison operator
/// \param lhs the first 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) {
return lhs.data == rhs.data;
}
@@ -646,7 +646,7 @@ struct matrix
/// \brief matrix comparison operator
/// \param lhs the first 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) {
return lhs.data != rhs.data;
}
@@ -666,7 +666,7 @@ struct matrix
///
/// \brief performs a linear algebraic matrix multiplication assignment
/// \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)
constexpr matrix<scalar_t, RowsV, OColIndicesV...>& operator*=(const matrix<scalar_t, ORowsV, OColIndicesV...>& rhs) {
return *this = *this * rhs;
@@ -682,7 +682,7 @@ public:
///
/// \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) {
return matrix_t(fennec::row(mat, ColIndicesV)...);
}

View File

@@ -103,7 +103,7 @@
/// \ref fennec_vector_not "bool not(bvec x)"<br>
/// <td width="50%" style="vertical-align: top">
/// \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>
///
/// </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
template<typename genBType = bool_t, size_t...i>
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
template<typename genBType = bool_t, size_t...i>
constexpr genBType all(const vector<genBType, i...>& x) {
@@ -210,10 +210,10 @@ constexpr genBType all(const vector<genBType, i...>& x) {
///
/// \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
/// \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
template<typename genBType = bool_t, size_t...i>
constexpr vector<genBType, i...> operator not(const vector<genBType, i...>& x) {

View File

@@ -41,7 +41,7 @@
///
/// \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.
///
/// 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>
/// \details Converts \f$degrees\f$ to \f$radians\f$, i.e., \f$degrees\cdot\frac{180}{\pi}\f$ <br><br>
/// \returns the angle \math{\theta} in \math{radians} <br><br>
/// \details Converts \emph{degrees} to \emph{radians}, i.e., \math{degrees\cdot\frac{180}{\pi}} <br><br>
///
/// \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>
constexpr genType radians(genType degrees) {
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>
/// \details Converts \f$radians\f$ to \f$degrees\f$, i.e., \f$radians\cdot\frac{\pi}{180}\f$ <br><br>
/// \returns the angle \math{\theta} in \emph{degrees} <br><br>
/// \details Converts \emph{radians} to \emph{degrees}, i.e., \math{radians\cdot\frac{\pi}{180}} <br><br>
///
/// \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>
constexpr genType degrees(genType radians) {
return genType(radians * 57.29577951308232087679815481410517);
@@ -195,11 +195,11 @@ constexpr genType degrees(genType radians) {
///
/// \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>
///
/// \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>
constexpr genType sin(genType x) {
return ::sin(x);
@@ -209,11 +209,11 @@ constexpr genType sin(genType x) {
///
/// \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>
///
/// \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>
constexpr genType cos(genType x) {
return ::cos(x);
@@ -223,11 +223,11 @@ constexpr genType cos(genType x) {
///
/// \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>
///
/// \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>
constexpr genType tan(genType 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
/// \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
/// \param x The Sine Value produced by \f$\theta\f$
/// \param x The Sine Value produced by \math{\theta}
template<typename genType>
constexpr genType asin(genType 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
/// \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
/// \param x The Cosine Value produced by \f$\theta\f$
/// \param x The Cosine Value produced by \math{\theta}
template<typename genType>
constexpr genType acos(genType 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
/// \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
/// \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>
constexpr genType atan(genType 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.
/// 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
/// \param y The Sine Value produced by \f$\theta\f$
/// \param x The Cosine Value produced by \f$\theta\f$
/// \param y The Sine Value produced by \math{\theta}
/// \param x The Cosine Value produced by \math{\theta}
template<typename genType>
constexpr genType atan(genType y, genType 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
/// \param x The Hyperbolic Angle \f$\alpha\f$
/// \param x The Hyperbolic Angle \math{\alpha}
template<typename genType>
constexpr genType sinh(genType 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>
constexpr genType cosh(genType 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>
constexpr genType tanh(genType x) {
return ::tanh(x);
@@ -355,10 +355,10 @@ constexpr genType tanh(genType x) {
///
/// \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>
///
/// \param x the hyperbolic angle \f$\alpha\f$
/// \param x the hyperbolic angle \math{\alpha}
template<typename genType, size_t...i>
constexpr genType asinh(genType x) {
return ::asinh(x);
@@ -368,10 +368,10 @@ constexpr genType asinh(genType x) {
///
/// \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>
///
/// \param x the hyperbolic angle \f$\alpha\f$
/// \param x the hyperbolic angle \math{\alpha}
template<typename genType, size_t...i>
constexpr genType acosh(genType x) {
return ::acosh(x);
@@ -381,10 +381,10 @@ constexpr genType acosh(genType x) {
///
/// \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>
///
/// \param x The Hyperbolic Angle \f$\alpha\f$
/// \param x The Hyperbolic Angle \math{\alpha}
template<typename genType, size_t...i>
constexpr genType atanh(genType x) {
return ::atanh(x);

View File

@@ -46,33 +46,33 @@
/// <table width="100%" class="fieldtable" id="table_fennec_math_vector_types">
/// <tr><th>Type <th>Corresponding Type <th>Brief
/// <tr><th colspan=3 style="text-align: center;">Floats
/// <tr><td>``\f$vec2\f$`` <td>\ref fennec::vec2 <td>\copybrief fennec::vec2
/// <tr><td>``\f$vec3\f$`` <td>\ref fennec::vec3 <td>\copybrief fennec::vec3
/// <tr><td>``\f$vec4\f$`` <td>\ref fennec::vec4 <td>\copybrief fennec::vec4
/// <tr><td>``\emph{vec2}`` <td>\ref fennec::vec2 <td>\copybrief fennec::vec2
/// <tr><td>``\emph{vec3}`` <td>\ref fennec::vec3 <td>\copybrief fennec::vec3
/// <tr><td>``\emph{vec4}`` <td>\ref fennec::vec4 <td>\copybrief fennec::vec4
/// <tr><th colspan=3 style="text-align: center;">Doubles
/// <tr><td>``\f$dvec2\f$``<td>\ref fennec::dvec2 <td>\copybrief fennec::dvec2
/// <tr><td>``\f$dvec3\f$``<td>\ref fennec::dvec3 <td>\copybrief fennec::dvec3
/// <tr><td>``\f$dvec4\f$``<td>\ref fennec::dvec4 <td>\copybrief fennec::dvec4
/// <tr><td>``\emph{dvec2}``<td>\ref fennec::dvec2 <td>\copybrief fennec::dvec2
/// <tr><td>``\emph{dvec3}``<td>\ref fennec::dvec3 <td>\copybrief fennec::dvec3
/// <tr><td>``\emph{dvec4}``<td>\ref fennec::dvec4 <td>\copybrief fennec::dvec4
/// <tr><th colspan=3 style="text-align: center;">Booleans
/// <tr><td>``\f$bvec2\f$`` <td>\ref fennec::bvec2 <td>\copybrief fennec::bvec2
/// <tr><td>``\f$bvec3\f$`` <td>\ref fennec::bvec3 <td>\copybrief fennec::bvec3
/// <tr><td>``\f$bvec4\f$`` <td>\ref fennec::bvec4 <td>\copybrief fennec::bvec4
/// <tr><td>``\emph{bvec2}`` <td>\ref fennec::bvec2 <td>\copybrief fennec::bvec2
/// <tr><td>``\emph{bvec3}`` <td>\ref fennec::bvec3 <td>\copybrief fennec::bvec3
/// <tr><td>``\emph{bvec4}`` <td>\ref fennec::bvec4 <td>\copybrief fennec::bvec4
/// <tr><th colspan=3 style="text-align: center;">Integers
/// <tr><td>``\f$ivec2\f$`` <td>\ref fennec::ivec2 <td>\copybrief fennec::ivec2
/// <tr><td>``\f$ivec3\f$`` <td>\ref fennec::ivec3 <td>\copybrief fennec::ivec3
/// <tr><td>``\f$ivec4\f$`` <td>\ref fennec::ivec4 <td>\copybrief fennec::ivec4
/// <tr><td>``\emph{ivec2}`` <td>\ref fennec::ivec2 <td>\copybrief fennec::ivec2
/// <tr><td>``\emph{ivec3}`` <td>\ref fennec::ivec3 <td>\copybrief fennec::ivec3
/// <tr><td>``\emph{ivec4}`` <td>\ref fennec::ivec4 <td>\copybrief fennec::ivec4
/// <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>``\f$uvec3\f$`` <td>\ref fennec::uvec3 <td>\copybrief fennec::uvec3
/// <tr><td>``\f$uvec4\f$`` <td>\ref fennec::uvec4 <td>\copybrief fennec::uvec4
/// <tr><td>``\emph{uvec2}`` <td>\ref fennec::uvec2 <td>\copybrief fennec::uvec2
/// <tr><td>``\emph{uvec3}`` <td>\ref fennec::uvec3 <td>\copybrief fennec::uvec3
/// <tr><td>``\emph{uvec4}`` <td>\ref fennec::uvec4 <td>\copybrief fennec::uvec4
/// </table>
///
///
///
/// \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$``.
/// Each component also has aliases for usage in colors ``\f$rgba\f$``, and texture coordinates ``\f$stpq\f$``. Accessing a
/// 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 \math{rgba}, and texture coordinates \math{stpq}. Accessing a
/// component outside the vector will cause an error at compile time, for example:
///
/// \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
/// used in any combination, with up to 4 components, to create another vector. For example, <br><br>
///
/// let \f$V = (0, 1, 2)\f$
/// then \f$V.xy = (0, 1)\f$
/// and \f$V.zy = (2, 1)\f$
/// let \math{V = (0, 1, 2)}
/// then \math{V.xy = (0, 1)}
/// and \math{V.zy = (2, 1)}
///
/// \section section_vectors_more More Info
/// - \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>```
/// \details 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, `(.*?)`
/// \tparam ScalarT The type of the Components
template<typename ScalarT>
using tvec2 = vec<ScalarT, 2>;
///
/// \brief Shorthand for creating a 3-element \ref fennec::vector, ```vec<ScalarT, 3>```
/// \details 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, `(.*?)`
/// \tparam ScalarT The type of the Components
template<typename ScalarT>
using tvec3 = vec<ScalarT, 3>;
///
/// \brief Shorthand for creating a 4-element \ref fennec::vector, ```vec<ScalarT, 4>```
/// \details 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, `(.*?)`
/// \tparam ScalarT The type of the Components
template<typename ScalarT>
using tvec4 = vec<ScalarT, 4>;
@@ -377,7 +377,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \brief decay implementation
///
/// \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() {
return static_cast<const decay_t&>(*this);
}
@@ -418,7 +418,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \brief copy assignment
///
/// \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
constexpr vector_t& operator=(const vector_t& rhs) {
return ((data[IndicesV] = rhs[IndicesV]), ..., *this);
@@ -428,7 +428,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \brief move assignment
///
/// \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
constexpr vector_t& operator=(vector_t&& rhs) noexcept {
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
///
/// \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 rhs right hand side
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
///
/// \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 rhs right hand side
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
///
/// \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 rhs right hand side
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
///
/// \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 rhs right hand side
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
///
/// \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 rhs right hand side
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
///
/// \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 rhs right hand side
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
/// \param lhs left 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) {
return vector_t((lhs[IndicesV] - rhs)...);
}
@@ -560,7 +560,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs left 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) {
return vector_t((lhs[IndicesV] * rhs)...);
}
@@ -571,7 +571,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs left 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) {
return vector((lhs[IndicesV] / rhs)...);
}
@@ -582,7 +582,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs left 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>) {
return vector((lhs[IndicesV] % rhs)...);
}
@@ -600,7 +600,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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) {
return ((lhs[IndicesV] += rhs), ..., lhs);
}
@@ -611,7 +611,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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) {
return ((lhs[IndicesV] -= rhs), ..., lhs);
}
@@ -622,7 +622,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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) {
return ((lhs[IndicesV] *= rhs), ..., lhs);
}
@@ -633,7 +633,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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) {
return ((lhs[IndicesV] /= rhs), ..., lhs);
}
@@ -644,7 +644,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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>) {
return ((lhs[IndicesV] %= rhs), ..., lhs);
}
@@ -661,7 +661,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
///
/// \details
/// \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) {
return vector((-x[IndicesV])...);
}
@@ -672,7 +672,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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) {
return vector((lhs[IndicesV] + rhs[IndicesV])...);
}
@@ -683,7 +683,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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) {
return vector((lhs[IndicesV] - rhs[IndicesV])...);
}
@@ -694,7 +694,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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) {
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
/// \param lhs Left 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) {
return vector((lhs[IndicesV] / rhs[IndicesV])...);
}
@@ -714,7 +714,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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>) {
return vector((lhs[IndicesV] % rhs[IndicesV])...);
}
@@ -732,7 +732,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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) {
return ((lhs[IndicesV] += rhs[IndicesV]), ..., lhs);
}
@@ -743,7 +743,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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) {
return ((lhs[IndicesV] -= rhs[IndicesV]), ..., lhs);
}
@@ -754,7 +754,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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) {
return ((lhs[IndicesV] *= rhs[IndicesV]), ..., lhs);
}
@@ -765,7 +765,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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) {
return ((lhs[IndicesV] /= rhs[IndicesV]), ..., lhs);
}
@@ -776,7 +776,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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>) {
return ((lhs[IndicesV] %= rhs[IndicesV]), ..., lhs);
}
@@ -793,7 +793,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
///
/// \details
/// \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) {
return vector_t(!x[IndicesV]...);
}
@@ -804,7 +804,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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>) {
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
/// \param lhs Left 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>) {
return vector_t((lhs[IndicesV] && rhs[IndicesV])...);
}
@@ -824,7 +824,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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>) {
return vector_t((lhs[IndicesV] || rhs)...);
}
@@ -835,7 +835,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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>) {
return vector_t((lhs[IndicesV] || rhs[IndicesV])...);
}
@@ -853,7 +853,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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>) {
return vector_t((lhs[IndicesV] & rhs)...);
}
@@ -864,7 +864,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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>) {
return vector_t((lhs[IndicesV] & rhs)...);
}
@@ -875,7 +875,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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>) {
return ((lhs[IndicesV] &= rhs), ..., lhs);
}
@@ -886,7 +886,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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>) {
return vector_t((lhs[IndicesV] & rhs[IndicesV])...);
@@ -898,7 +898,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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>) {
return ((lhs[IndicesV] &= rhs[IndicesV]), ..., lhs);
}
@@ -910,7 +910,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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>) {
return vector_t((lhs[IndicesV] | rhs)...);
}
@@ -921,7 +921,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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>) {
return vector_t((lhs[IndicesV] | rhs)...);
}
@@ -932,7 +932,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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>) {
return ((lhs[IndicesV] |= rhs), ..., lhs);
}
@@ -943,7 +943,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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>) {
return vector_t((lhs[IndicesV] | rhs[IndicesV])...);
@@ -955,7 +955,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \details
/// \param lhs Left 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>) {
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
/// \param lhs Left 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>) {
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
/// \param lhs Left 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>) {
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
/// \param lhs Left 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>) {
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
/// \param lhs Left 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>) {
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
/// \param lhs Left 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>) {
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
/// \param lhs Left 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>) {
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
/// \param lhs Left 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>) {
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
/// \param lhs Left 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>) {
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
/// \param lhs Left 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>) {
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
/// \param lhs Left 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>) {
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
/// \param lhs Left 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>) {
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
/// \param lhs Left 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>) {
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
/// \param lhs Left 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>) {
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
/// \param lhs Left 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>) {
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
/// \param lhs Left 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>) {
return ((lhs[IndicesV] >>= rhs[IndicesV]), ..., lhs);
}

View File

@@ -25,6 +25,12 @@
#pragma GCC diagnostic ignored "-Wpedantic"
#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
#pragma warning(push)
#pragma warning(disable:4201)
@@ -617,4 +623,12 @@ namespace fennec::detail
#pragma GCC diagnostic pop
#endif
#ifdef FENNEC_COMPILER_CLANG
#pragma clang diagnostic pop
#endif
#if FENNEC_COMPILER_MSVC
#pragma warning(pop)
#endif
#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>>{};
///
/// \brief shorthand for ```is_vector<T>::value```
/// \brief shorthand for `(.*?)`
/// \tparam T type to check
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
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
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>{};
///
/// \brief shorthand for ```component_count<T>::value```
/// \brief shorthand for `(.*?)`
/// \tparam Ts types to accumulate the count of
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
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
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;
// 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
template<typename T>
class allocator
@@ -166,39 +161,39 @@ public:
///
/// \brief Copy Assignment
/// \returns A reference to self
/// \returns A reference to \emph{this}
constexpr allocator& operator=(const allocator&) = default;
///
/// \brief Equality operator
/// \returns \f$true\f$
/// \returns \emph{true}
constexpr bool_t operator==(const allocator&) {
return true;
}
///
/// \brief Inequality operator
/// \returns \f$false\f$
/// \returns \emph{false}
constexpr bool_t operator!=(const allocator&) {
return false;
}
///
/// \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>&) {
return false;
}
///
/// \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>&) {
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
/// \returns A pointer to the allocated block
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 align The alignment
/// \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
constexpr void deallocate(T* 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 align The alignment
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
template<typename T>
class allocator<T[]>
@@ -260,40 +255,40 @@ public:
///
/// \brief Copy Assignment
/// \returns A reference to self
/// \returns A reference to \emph{this}
constexpr allocator& operator=(const allocator&) = default;
///
/// \brief Equality operator
/// \returns \f$true\f$
/// \returns \emph{true}
constexpr bool_t operator==(const allocator&) {
return true;
}
///
/// \brief Inequality operator
/// \returns \f$false\f$
/// \returns \emph{false}
constexpr bool_t operator!=(const allocator&) {
return false;
}
///
/// \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>&) {
return false;
}
///
/// \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>&) {
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
/// \returns A pointer to the allocated block
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 align The alignment
/// \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
constexpr void deallocate(T* 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 align The alignment
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
: _data(nullptr), _capacity(0), _alignment(zero<align_t>()) {
}
///
/// \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
: _data(nullptr), _capacity(0), _alignment(zero<align_t>()) {
allocate(n);
@@ -389,7 +384,7 @@ public:
///
/// \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
constexpr allocation(size_t n, align_t align) noexcept
: _data(nullptr)
@@ -413,7 +408,7 @@ public:
/// \brief Allocator Constructor
/// \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
: _alloc(alloc)
, _data(nullptr)
@@ -423,10 +418,10 @@ public:
///
/// \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.
///
/// \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
: _alloc(alloc)
, _data(nullptr)
@@ -442,7 +437,7 @@ public:
/// \param n the number of elements
/// \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)
: allocation(n, alloc) {
fennec::memmove(static_cast<void*>(_data), data, n);
@@ -450,11 +445,11 @@ public:
///
/// \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 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
: _alloc(alloc)
, _data(nullptr)
@@ -471,7 +466,7 @@ public:
/// \param align The alignment of the allocation
/// \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)
: allocation(n, align, alloc) {
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
/// \param alloc The allocation to move
constexpr allocation(allocation&& alloc) noexcept
@@ -522,7 +517,7 @@ public:
///
/// \brief Copy Assignment Operator
/// \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) {
allocation::allocate(alloc.capacity(), alloc.alignment());
fennec::memmove(_data, alloc, size());
@@ -532,7 +527,7 @@ public:
///
/// \brief Move Assignment Operator
/// \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 {
// 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
constexpr size_t capacity() const {
return _capacity;
@@ -588,7 +583,7 @@ public:
/// \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
constexpr void allocate(size_t n, align_t align = zero<align_t>()) noexcept {
deallocate();
@@ -620,7 +615,7 @@ public:
/// \brief Reallocate the block with a new size.
/// 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
constexpr void reallocate(size_t n, align_t align = zero<align_t>()) noexcept {
if (_data == nullptr) {
@@ -628,7 +623,8 @@ public:
return;
}
value_t* old = _data; size_t old_cap = _capacity;
value_t* old = _data;
const size_t old_cap = _capacity;
_data = nullptr;
allocate(n, align);
@@ -655,7 +651,7 @@ public:
///
/// \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) {
assertd(i < capacity(), "Array Out of Bounds");
return _data[i];
@@ -664,7 +660,7 @@ public:
///
/// \brief Array Access Operator
/// \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 {
assertd(i < capacity(), "Array Out of Bounds");
return _data[i];

View File

@@ -89,27 +89,27 @@ public:
///
/// \brief Array Access Operator
/// \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) {
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];
}
///
/// \brief Const Array Access Operator
/// \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 {
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];
}
///
/// \brief Cast Function
/// \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>
constexpr T* cast() {
void* temp = _arr;
@@ -119,7 +119,7 @@ public:
///
/// \brief Const Cast Function
/// \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>
constexpr const T* cast() const {
const void* temp = _carr;
@@ -166,8 +166,8 @@ struct hash<byte_array> {
h *= m;
}
const uint8_t* b = (const uint8_t*)x;
switch (n & 7) {
const uint8_t* b = reinterpret_cast<const uint8_t*>(x);
switch (n & 0x7) {
case 7: h ^= uint64_t(b[6]) << 48; __attribute__((fallthrough));
case 6: h ^= uint64_t(b[5]) << 40; __attribute__((fallthrough));
case 5: h ^= uint64_t(b[4]) << 32; __attribute__((fallthrough));

View File

@@ -38,6 +38,8 @@
namespace fennec
{
// addressof ===========================================================================================================
///
/// \brief Returns the address of an object regardless of whether the `&` operators is implemented.
/// \tparam TypeT The type of the objects
@@ -48,24 +50,45 @@ constexpr TypeT* addressof(TypeT& 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 ch The byte to search for
/// \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.
using ::memchr;
using ::wmemchr;
/// \returns A pointer to the location of \emph{ch}, otherwise \emph{nullptr} if \emph{ch} is not found.
constexpr const void* memchr(const void* arr, int ch, size_t n) {
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 rhs The second object, interpreted as an array of bytes
/// \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$
/// for the first byte \f$b\f$ where \f$lhs[b] > \f$ rhs[b]\f$, and \f$-1\f$ for \f$
using ::memcmp;
using ::wmemcmp;
/// \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 \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(const void* lhs, const void* rhs, size_t n) {
return ::memcmp(lhs, rhs, n);
}
///
/// \brief Safe version of memcmp
@@ -73,26 +96,58 @@ using ::wmemcmp;
/// \param rhs The second object, interpreted as an array of bytes
/// \param n0 The size, in bytes, of lhs
/// \param n1 The size, in bytes, of rhs
/// \returns \f$0\f$ if the first \f$min(n0, n1)\f$ bytes of \f$lhs\f$ and \f$rhs\f$ are equivalent. Otherwise, returns \f$1\f$
/// for the first byte \f$b\f$ where \f$lhs[b] > \f$ rhs[b]\f$, and \f$-1\f$ for \f$
/// \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 \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) {
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 src The source object, interpreted as an array of bytes
/// \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
/// 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
/// \f$src\f$ will be repeated in \f$dst\f$ with a period of \f$k\f$.
/// \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.
using ::memcpy;
using ::wmemcpy;
constexpr void* memcpy(void* dst, const void* src, size_t n) {
return ::memcpy(dst, src, n);
}
///
/// \brief Safe version of memcpy
@@ -100,19 +155,64 @@ using ::wmemcpy;
/// \param src The source object, interpreted as an array of bytes
/// \param n0 The size, in bytes, of dst
/// \param n1 The size, in bytes, of src
/// \returns \f$dst\f$
/// \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) {
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 src The source object, interpreted as an array of bytes
/// \param n The number of bytes to copy
/// \returns \f$dst\f$
using ::memmove;
using ::wmemmove;
/// \returns \emph{dst}
constexpr void* memmove(void* dst, const void* src, size_t n) {
return ::memmove(dst, src, n);
}
///
/// \brief Safe version of memmove
@@ -120,19 +220,54 @@ using ::wmemmove;
/// \param src The source object, interpreted as an array of bytes
/// \param n0 The size, in bytes, of dst
/// \param n1 The size, in bytes, of src
/// \returns \f$dst\f$
/// \returns \emph{dst}
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 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
/// \returns \f$dst\f$
using ::memset;
using ::wmemset;
constexpr void memset(void* dst, int ch, size_t n) {
::memset(dst, ch, n);
}
///
/// \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
// implementation
#if FENNEC_COMPILER_GCC
#if FENNEC_GLIBC
#ifndef __OPTIMIZE__
# define __OPTIMIZE__
#else
@@ -34,7 +34,7 @@
#include <string.h>
#include <wchar.h>
#if FENNEC_COMPILER_GCC
#if FENNEC_GLIBC
#ifndef FENNEC_OPTIMIZE_FOUND
#undef __OPTIMIZE__
#endif

View File

@@ -54,7 +54,7 @@ struct nothrow_t
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
/// \param ptr the pointer to the object to construct
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
/// \param ptr the pointer to the object to construct
/// \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
/// \param ptr the pointer to the object to construct
/// \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 ArgsT the argument types
/// \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
/// \param ptr the pointer to the object to destruct
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
template<typename TypeT>
struct default_delete
@@ -42,7 +42,7 @@ struct default_delete
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
constexpr void operator()(TypeT* ptr) const noexcept {
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 {}
///
/// \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
template<class ArrT> requires requires { is_convertible_v<ArrT(*)[], TypeT(*)[]> == true; }
constexpr void operator()(TypeT* ptr) const noexcept {
@@ -122,7 +122,7 @@ public:
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 del The deleter
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
template<typename DerivedT> requires(is_base_of_v<TypeT, DerivedT>)
constexpr unique_ptr(unique_ptr<DerivedT>&& other)
: _handle(other.release()) {
}
// Delete copy constructor
///
/// \brief Copy Constructor
/// \details Deleted
constexpr unique_ptr(const unique_ptr&) = delete;
///
@@ -166,18 +168,21 @@ public:
///
/// \brief move constructor
/// \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 {
_delete = r._delete;
fennec::swap(_handle, r._handle);
return *this;
}
/// @}
private:
///
/// \brief Copy Assignment
/// \details Deleted
/// \returns Deleted
constexpr unique_ptr& operator=(const unique_ptr&) = delete;
/// @}
// Properties ==========================================================================================================
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() {
return _handle == nullptr;
}
///
/// \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 {
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 ArgsT The constructor arguments, automatically deduced
/// \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>
unique_ptr<TypeT> make_unique(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:
///
/// For a server type \f$DisplayT\f$; any \f$gfxcontext\f$ implementation that wishes to implement \f$DisplayT\f$
/// must provide a constructor that accepts a `DisplayT*`. `DisplayT::ctx_registry::register_type` must then be
/// called for the \f$gfxcontext\f$ implementation.
/// For a server type \emph{DisplayT}; any `gfxcontext` implementation that wishes to implement \emph{DisplayT}
/// must provide a constructor that accepts a \emph{DisplayT*}. `DisplayT::ctx_registry::register_type()` must then be
/// called for the `gfxcontext` implementation.
class display_server : public type_registry<display_server, platform*> {
// Definitions & Constants =============================================================================================
public:
@@ -136,13 +136,13 @@ public:
///
/// \brief feature support checking function
/// \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 {
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;
/// @}

View File

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

View File

@@ -164,15 +164,21 @@ public:
///
/// \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
window* get_parent() const { return parent; }
window* get_parent() const {
return parent;
}
///
/// \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
@@ -208,19 +214,29 @@ public:
///
/// \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
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
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
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
/// \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); }
///
/// \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); }
///
/// \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); }
///
/// \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); }
/// @}
@@ -265,48 +281,48 @@ public:
///
/// \brief tests a specific 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); }
///
/// \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); }
///
/// \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); }
///
/// \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); }
///
/// \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); }
///
/// \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); }
///
/// \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); }
///
/// \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); }
///
/// \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); }
@@ -314,55 +330,55 @@ public:
/// \brief sets a specific flag
/// \param flag the flag from `window::flag_`
/// \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;
///
/// \brief sets whether to always be on top of other windows
/// \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); }
///
/// \brief sets whether to have no window decorations
/// \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); }
///
/// \brief sets whether to be modal
/// \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); }
///
/// \brief sets whether to pass mouse input to windows underneath from the same application
/// \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); }
///
/// \brief sets whether the window is a popup
/// \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); }
///
/// \brief sets whether to be resizable
/// \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); }
///
/// \brief sets whetherto be transparent
/// \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); }
///
/// \brief sets whether to be unfocusable
/// \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); }
/// @}
@@ -385,10 +401,12 @@ public:
// Protected Member Variables ==========================================================================================
protected:
public:
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
window* const root; //!< the nearest top-level window in the hierarchy
protected:
config cfg; //!< the current configuration
state state; //!< the current state
unique_ptr<gfxsurface> gfx_surface; //!< the corresponding graphics surface

View File

@@ -23,6 +23,8 @@
namespace fennec
{
///
/// \brief Platform Implementation for Linux-Based Operating Systems
class linux_platform : public unix_platform {
// Constructors & Destructor ===========================================================================================
@@ -31,7 +33,7 @@ public:
/// \name Constructors & Destructor ================================================================================
/// @{
/// \brief constructor
/// \brief Linux Platform Constructor
linux_platform()
: unix_platform() {
}
@@ -39,11 +41,18 @@ public:
/// @}
//
// Initialization ======================================================================================================
/// \name Initialization
/// @{
void initialize() override; //!< platform initialization
void shutdown() override; //!< platform shutdown
/// @}
private:
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
#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
* recursively through the tree of surfaces.
*
* The behaviour of a wl_surface.commit request on a sub-surface
* depends on the sub-surface's mode. The possible modes are
* synchronized and desynchronized, see methods
* 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.
* A sub-surface can be in one of two modes. The possible modes are
* synchronized and desynchronized, see methods wl_subsurface.set_sync and
* wl_subsurface.set_desync.
*
* The main surface can be thought to be always in desynchronized mode,
* 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
* 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
* 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,
@@ -899,23 +894,9 @@ extern const struct wl_interface wl_subcompositor_interface;
* hidden, or if a NULL wl_buffer is applied. These rules apply
* recursively through the tree of surfaces.
*
* The behaviour of a wl_surface.commit request on a sub-surface
* depends on the sub-surface's mode. The possible modes are
* synchronized and desynchronized, see methods
* 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.
* A sub-surface can be in one of two modes. The possible modes are
* synchronized and desynchronized, see methods wl_subsurface.set_sync and
* wl_subsurface.set_desync.
*
* The main surface can be thought to be always in desynchronized mode,
* 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
* 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
* 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,
@@ -1307,6 +1297,7 @@ wl_callback_destroy(struct wl_callback *wl_callback)
#define WL_COMPOSITOR_CREATE_SURFACE 0
#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
*/
#define WL_COMPOSITOR_CREATE_REGION_SINCE_VERSION 1
/**
* @ingroup iface_wl_compositor
*/
#define WL_COMPOSITOR_RELEASE_SINCE_VERSION 7
/** @ingroup iface_wl_compositor */
static inline void
@@ -1377,6 +1372,18 @@ wl_compositor_create_region(struct wl_compositor *wl_compositor)
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_DESTROY 1
#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
* 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
* 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
*/
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 */
@@ -1991,6 +2079,11 @@ struct wl_shm_listener {
*
* Informs the client about a valid pixel format that can be used
* 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
*/
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_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
*/
#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 */
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;
}
/**
* @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
#define WL_SHELL_ERROR_ENUM
enum wl_shell_error {
@@ -3691,6 +3802,10 @@ enum wl_surface_error {
* surface was destroyed before its role object
*/
WL_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT = 4,
/**
* no buffer was attached
*/
WL_SURFACE_ERROR_NO_BUFFER = 5,
};
#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_DAMAGE_BUFFER 9
#define WL_SURFACE_OFFSET 10
#define WL_SURFACE_GET_RELEASE 11
/**
* @ingroup iface_wl_surface
@@ -3857,6 +3973,10 @@ wl_surface_add_listener(struct wl_surface *wl_surface,
* @ingroup iface_wl_surface
*/
#define WL_SURFACE_OFFSET_SINCE_VERSION 5
/**
* @ingroup iface_wl_surface
*/
#define WL_SURFACE_GET_RELEASE_SINCE_VERSION 7
/** @ingroup iface_wl_surface */
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,
* the delivery of wl_buffer.release events becomes undefined. A well
* behaved client should not rely on wl_buffer.release events in this
* case. Alternatively, a client could create multiple wl_buffer objects
* from the same backing storage or use a protocol extension providing
* per-commit release notifications.
* case. Instead, clients hitting this case should use
* wl_surface.get_release or use a protocol extension providing per-commit
* 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
* 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,
* 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
* to affect double-buffered 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
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);
}
/**
* @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
#define WL_SEAT_CAPABILITY_ENUM
/**
@@ -6344,20 +6526,18 @@ wl_subsurface_destroy(struct wl_subsurface *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
* corner pixel) will be at the location x, y of the parent surface
* coordinate system. The coordinates are not restricted to the parent
* 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.
*
* Position is double-buffered state on the parent surface, see
* wl_subsurface and wl_surface.commit for more information.
*/
static inline void
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,
* 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
* 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
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
*
* The sub-surface is placed just below the reference surface.
*
* See wl_subsurface.place_above.
*/
static inline void
@@ -6407,18 +6586,9 @@ wl_subsurface_place_below(struct wl_subsurface *wl_subsurface, struct wl_surface
* @ingroup iface_wl_subsurface
*
* 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
* 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.
* See wl_subsurface and wl_surface.commit for more information.
*/
static inline void
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
*
* 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
* 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.
* See wl_subsurface and wl_surface.commit for more information.
*/
static inline void
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
#define XDG_SHELL_CLIENT_PROTOCOL_H

View File

@@ -173,7 +173,7 @@
</event>
</interface>
<interface name="wl_callback" version="1">
<interface name="wl_callback" version="1" frozen="true">
<description summary="callback object">
Clients can handle the 'done' event to get notified when
the related request is done.
@@ -190,7 +190,7 @@
</event>
</interface>
<interface name="wl_compositor" version="6">
<interface name="wl_compositor" version="7">
<description summary="the compositor singleton">
A compositor. This object is a singleton global. The
compositor is in charge of combining the contents of multiple
@@ -210,6 +210,14 @@
</description>
<arg name="id" type="new_id" interface="wl_region" summary="the new region"/>
</request>
<!-- Version 7 additions -->
<request name="release" type="destructor" since="7">
<description summary="destroy wl_compositor">
This request destroys the wl_compositor. This has no effect on any other objects.
</description>
</request>
</interface>
<interface name="wl_shm_pool" version="2">
@@ -304,7 +312,8 @@
The drm format codes match the macros defined in drm_fourcc.h, except
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
extension, pre-multiplied alpha is used for pixel values.
@@ -434,6 +443,26 @@
<entry name="avuy8888" value="0x59555641" summary="[31:0] A:Cr:Cb:Y 8:8:8:8 little endian"/>
<entry name="xvuy8888" value="0x59555658" summary="[31:0] X:Cr:Cb:Y 8:8:8:8 little endian"/>
<entry name="p030" value="0x30333050" summary="2x2 subsampled Cr:Cb plane 10 bits per channel packed"/>
<entry name="rgb161616" value="0x38344752" summary="[47:0] R:G:B 16:16:16 little endian"/>
<entry name="bgr161616" value="0x38344742" summary="[47:0] B:G:R 16:16:16 little endian"/>
<entry name="r16f" value="0x48202052" summary="[15:0] R 16 little endian"/>
<entry name="gr1616f" value="0x48205247" summary="[31:0] G:R 16:16 little endian"/>
<entry name="bgr161616f" value="0x48524742" summary="[47:0] B:G:R 16:16:16 little endian"/>
<entry name="r32f" value="0x46202052" summary="[31:0] R 32 little endian"/>
<entry name="gr3232f" value="0x46205247" summary="[63:0] R:G 32:32 little endian"/>
<entry name="bgr323232f" value="0x46524742" summary="[95:0] R:G:B 32:32:32 little endian"/>
<entry name="abgr32323232f" value="0x46384241" summary="[127:0] R:G:B:A 32:32:32:32 little endian"/>
<entry name="nv20" value="0x3032564e" summary="2x1 subsampled Cr:Cb plane"/>
<entry name="nv30" value="0x3033564e" summary="non-subsampled Cr:Cb plane"/>
<entry name="s010" value="0x30313053" summary="2x2 subsampled Cb (1) and Cr (2) planes 10 bits per channel"/>
<entry name="s210" value="0x30313253" summary="2x1 subsampled Cb (1) and Cr (2) planes 10 bits per channel"/>
<entry name="s410" value="0x30313453" summary="non-subsampled Cb (1) and Cr (2) planes 10 bits per channel"/>
<entry name="s012" value="0x32313053" summary="2x2 subsampled Cb (1) and Cr (2) planes 12 bits per channel"/>
<entry name="s212" value="0x32313253" summary="2x1 subsampled Cb (1) and Cr (2) planes 12 bits per channel"/>
<entry name="s412" value="0x32313453" summary="non-subsampled Cb (1) and Cr (2) planes 12 bits per channel"/>
<entry name="s016" value="0x36313053" summary="2x2 subsampled Cb (1) and Cr (2) planes 16 bits per channel"/>
<entry name="s216" value="0x36313253" summary="2x1 subsampled Cb (1) and Cr (2) planes 16 bits per channel"/>
<entry name="s416" value="0x36313453" summary="non-subsampled Cb (1) and Cr (2) planes 16 bits per channel"/>
</enum>
<request name="create_pool">
@@ -454,6 +483,10 @@
Informs the client about a valid pixel format that
can be used 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.
</description>
<arg name="format" type="uint" enum="format" summary="buffer pixel format"/>
</event>
@@ -470,7 +503,7 @@
</request>
</interface>
<interface name="wl_buffer" version="1">
<interface name="wl_buffer" version="1" frozen="true">
<description summary="content for a wl_surface">
A buffer provides the content for a wl_surface. Buffers are
created through factory interfaces such as wl_shm, wp_linux_buffer_params
@@ -518,7 +551,7 @@
</event>
</interface>
<interface name="wl_data_offer" version="3">
<interface name="wl_data_offer" version="4">
<description summary="offer to transfer data">
A wl_data_offer represents a piece of data offered for transfer
by another client (the source client). It is used by the
@@ -711,7 +744,7 @@
</event>
</interface>
<interface name="wl_data_source" version="3">
<interface name="wl_data_source" version="4">
<description summary="offer to transfer data">
The wl_data_source object is the source side of a wl_data_offer.
It is created by the source client in a data transfer and
@@ -866,7 +899,7 @@
</event>
</interface>
<interface name="wl_data_device" version="3">
<interface name="wl_data_device" version="4">
<description summary="data transfer device">
There is one wl_data_device per seat which can be obtained
from the global wl_data_device_manager singleton.
@@ -1027,7 +1060,7 @@
</request>
</interface>
<interface name="wl_data_device_manager" version="3">
<interface name="wl_data_device_manager" version="4">
<description summary="data transfer interface">
The wl_data_device_manager is a singleton global object that
provides access to inter-client data transfer mechanisms such as
@@ -1089,6 +1122,15 @@
<entry name="move" value="2" summary="move action"/>
<entry name="ask" value="4" summary="ask action"/>
</enum>
<!-- Version 4 additions -->
<request name="release" type="destructor" since="4">
<description summary="destroy wl_data_device_manager">
This request destroys the wl_data_device_manager. This has no effect on any other
objects.
</description>
</request>
</interface>
<interface name="wl_shell" version="1">
@@ -1395,7 +1437,7 @@
</event>
</interface>
<interface name="wl_surface" version="6">
<interface name="wl_surface" version="7">
<description summary="an onscreen surface">
A surface is a rectangular area that may be displayed on zero
or more outputs, and shown any number of times at the compositor's
@@ -1451,6 +1493,7 @@
<entry name="invalid_offset" value="3" summary="buffer offset is invalid"/>
<entry name="defunct_role_object" value="4"
summary="surface was destroyed before its role object"/>
<entry name="no_buffer" value="5" summary="no buffer was attached"/>
</enum>
<request name="destroy" type="destructor">
@@ -1505,9 +1548,11 @@
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
behaved client should not rely on wl_buffer.release events in this
case. Alternatively, a client could create multiple wl_buffer objects
from the same backing storage or use a protocol extension providing
per-commit release notifications.
case. Instead, clients hitting this case should use
wl_surface.get_release or use a protocol extension providing per-commit
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
the surface contents. Destroying the wl_buffer before wl_buffer.release
@@ -1667,21 +1712,48 @@
etc.) is double-buffered. Protocol requests modify the pending state,
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
to affect double-buffered 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.
</description>
</request>
@@ -1884,6 +1956,32 @@
<arg name="transform" type="uint" enum="wl_output.transform"
summary="preferred transform"/>
</event>
<!-- Version 7 additions -->
<request name="get_release" since="7">
<description summary="get a release callback">
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.
</description>
<arg name="callback" type="new_id" interface="wl_callback" summary="callback object for the release"/>
</request>
</interface>
<interface name="wl_seat" version="10">
@@ -3002,7 +3100,7 @@
</event>
</interface>
<interface name="wl_region" version="1">
<interface name="wl_region" version="7">
<description summary="region interface">
A region object describes an area.
@@ -3120,23 +3218,9 @@
hidden, or if a NULL wl_buffer is applied. These rules apply
recursively through the tree of surfaces.
The behaviour of a wl_surface.commit request on a sub-surface
depends on the sub-surface's mode. The possible modes are
synchronized and desynchronized, see methods
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.
A sub-surface can be in one of two modes. The possible modes are
synchronized and desynchronized, see methods wl_subsurface.set_sync and
wl_subsurface.set_desync.
The main surface can be thought to be always in desynchronized mode,
since it does not have a parent in the sub-surfaces sense.
@@ -3148,6 +3232,15 @@
synchronized mode, and then assume that all its child and grand-child
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
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,
@@ -3178,20 +3271,18 @@
<request name="set_position">
<description summary="reposition the sub-surface">
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
corner pixel) will be at the location x, y of the parent surface
coordinate system. The coordinates are not restricted to the parent
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.
Position is double-buffered state on the parent surface, see
wl_subsurface and wl_surface.commit for more information.
</description>
<arg name="x" type="int" summary="x coordinate in the parent surface"/>
<arg name="y" type="int" summary="y coordinate in the parent surface"/>
@@ -3205,13 +3296,11 @@
parent surface. Using any other surface, including this sub-surface,
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
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.
</description>
<arg name="sibling" type="object" interface="wl_surface"
summary="the reference surface"/>
@@ -3220,6 +3309,7 @@
<request name="place_below">
<description summary="restack the sub-surface">
The sub-surface is placed just below the reference surface.
See wl_subsurface.place_above.
</description>
<arg name="sibling" type="object" interface="wl_surface"
@@ -3229,42 +3319,18 @@
<request name="set_sync">
<description summary="set sub-surface to synchronized mode">
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
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.
See wl_subsurface and wl_surface.commit for more information.
</description>
</request>
<request name="set_desync">
<description summary="set sub-surface to desynchronized mode">
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
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.
See wl_subsurface and wl_surface.commit for more information.
</description>
</request>
</interface>

View File

@@ -81,7 +81,7 @@ public:
void connect() override; //!< connect to 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

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 =====================================================================================================
public:
@@ -86,7 +88,7 @@ public:
/// \brief sets a specific flag
/// \param flag the flag from `window::flag_`
/// \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;
/// @}

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;
private:

View File

@@ -37,7 +37,7 @@
/// \brief convert egl error to a readable string
/// \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) {
switch (err) {
case EGL_SUCCESS: return "None";

File diff suppressed because it is too large Load Diff

View File

@@ -104,12 +104,13 @@ public:
/// \brief destructor
~window_manager();
/// @}
private:
///
/// \brief Copy Constructor
/// \details Deleted, no semantics for copying a platform
window_manager(const window_manager&) = delete;
/// @}
// Initialization & Update =============================================================================================
public:
@@ -247,7 +248,7 @@ public:
/// \brief tests if the window is visible
///
/// \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 {
lock_guard guard(_lock);
return _check_state(window, window::state_visible);
@@ -257,7 +258,7 @@ public:
/// \brief tests if the window is a child
///
/// \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 {
lock_guard guard(_lock);
return _check_state(window, window::state_child);
@@ -267,7 +268,7 @@ public:
/// \brief tests if the window is running
///
/// \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 {
lock_guard guard(_lock);
return _check_state(window, window::state_running);
@@ -277,7 +278,7 @@ public:
/// \brief tests if the window is suspended
///
/// \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 {
lock_guard guard(_lock);
return _check_state(window, window::state_suspended);
@@ -297,7 +298,7 @@ public:
///
/// \param window The window.
/// \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) {
lock_guard guard(_lock);
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
///
/// \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) {
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
///
/// \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) {
return get_flag(window, window::flag_borderless);
}
@@ -326,7 +327,7 @@ public:
/// \brief check if the window is flagged to be modal
///
/// \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) {
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
///
/// \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) {
return get_flag(window, window::flag_pass_mouse);
}
@@ -344,7 +345,7 @@ public:
/// \brief check if the window is flagged as a popup
///
/// \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) {
return get_flag(window, window::flag_popup);
}
@@ -353,7 +354,7 @@ public:
/// \brief check if the window is flagged to be resizable
///
/// \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) {
return get_flag(window, window::flag_resizable);
}
@@ -362,7 +363,7 @@ public:
/// \brief check if the window is flagged to be transparent
///
/// \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) {
return get_flag(window, window::flag_transparent);
}
@@ -371,7 +372,7 @@ public:
/// \brief check if the window is flagged to be unfocusable
///
/// \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) {
return get_flag(window, window::flag_no_focus);
}
@@ -398,7 +399,6 @@ public:
///
/// \param window The window.
/// \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) {
return set_flag(window, window::flag_always_on_top, val);
}
@@ -408,7 +408,6 @@ public:
///
/// \param window The window.
/// \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) {
return set_flag(window, window::flag_borderless, val);
}
@@ -418,7 +417,6 @@ public:
///
/// \param window The window.
/// \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) {
return set_flag(window, window::flag_modal, val);
}
@@ -428,7 +426,6 @@ public:
///
/// \param window The window.
/// \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) {
return set_flag(window, window::flag_pass_mouse, val);
}
@@ -438,7 +435,6 @@ public:
///
/// \param window The window.
/// \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) {
return set_flag(window, window::flag_popup, val);
}
@@ -448,7 +444,6 @@ public:
///
/// \param window The window.
/// \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) {
return set_flag(window, window::flag_resizable, val);
}
@@ -458,7 +453,6 @@ public:
///
/// \param window The window.
/// \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) {
return set_flag(window, window::flag_transparent, val);
}
@@ -468,7 +462,6 @@ public:
///
/// \param window The window.
/// \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) {
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;
///
/// \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() {
}
// 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 ======================================================================================================
///
@@ -259,6 +273,9 @@ enum types : GLenum {
UINT_ATOMIC_COUNTER = GL_UNSIGNED_INT_ATOMIC_COUNTER, //!< Atomic Counter
};
// Pixel Components ====================================================================================================
///
/// \brief OpenGL Pixel Components
enum pixel_components : GLenum {
@@ -287,10 +304,13 @@ enum pixel_components : GLenum {
DEPTH_STENCIL = GL_DEPTH_STENCIL, //!< Combined Depth-Stencil
};
// Pixel Formats =======================================================================================================
///
/// \brief OpenGL Color Formats
/// \note UNORM formats are integers interpreted in the normalized range \f$[0.0, 1.0]\f$
/// \note SNORM formats are integers interpreted in the normalized range \f$[-1.0, 1.0]\f$
/// \brief OpenGL Pixel Formats
/// \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 \math{[-1.0, 1.0]}
enum pixel_formats : GLint {
R8_UNORM = GL_R8, //!< 8-Bit Unsigned 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
};
// 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
#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/string/cstring.h>
@@ -44,6 +44,12 @@ namespace fennec::vk
/// \brief Wrapper class for VkApplicationInfo
struct app_info : private VkApplicationInfo {
// Definitions =========================================================================================================
private:
// Constructors & Destructor ===========================================================================================
public:
@@ -52,30 +58,36 @@ public:
///
/// \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
/// until a structure of type fennec::vk::instance is constructed
/// \param app_name the name 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
/// until a structure of type fennec::vk::instance is constructed
/// \param engine_name the name 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
/// object until a structure of type fennec::vk::instance is constructed
/// TODO: DEFINE EXTENSION STRUCTURE WRAPPERS
app_info(
const cstring& app_name = {}, const version& app_version = {},
const cstring& engine_name = {}, const version& engine_version = {},
const version& api_version = {},
void* ext = nullptr
const cstring& engine_name = {}, const version& engine_version = {}
) noexcept : VkApplicationInfo {
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.pNext = ext,
.pApplicationName = app_name,
.pNext = nullptr,
.pApplicationName = nullptr,
.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),
.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
/// \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;
///
/// \brief Move Assignment
/// \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;
/// @}
@@ -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 {
return this;
}
///
/// \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 {
return this;
}
@@ -168,18 +180,22 @@ public:
///
/// \brief Set the engine version
/// \param ver A version struct containing the new version
void set_engine_version(const version& ver) {
engineVersion = VK_MAKE_VERSION(ver.major, ver.minor, ver.patch);
void set_app_version(const version& ver) {
applicationVersion = VK_MAKE_VERSION(ver.major, ver.minor, ver.patch);
}
///
/// \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
/// \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
@@ -203,7 +219,9 @@ public:
version get_api_version() const {
return version {
.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) {
pNext = nullptr;
}
@@ -232,6 +250,8 @@ public:
// Private Member Variables ============================================================================================
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