- Started setting up a thread safe window manager

- Created thread & atomic structures
This commit is contained in:
2025-12-17 01:11:28 -05:00
parent 520a0e1363
commit aee4e340dd
41 changed files with 2179 additions and 428 deletions

View File

@@ -16,13 +16,13 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# ======================================================================================================================
cmake_minimum_required(VERSION 3.28)
cmake_minimum_required(VERSION 3.28...3.31)
project(fennec)
set(FENNEC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
macro(fennec_add_sources)
list(APPEND FENNEC_EXTRA_SOURCES ${ARGN})
list(APPEND FENNEC_SOURCES ${ARGN})
endmacro()
macro(fennec_add_definitions)
@@ -37,6 +37,10 @@ macro(fennec_add_shared_libraries)
list(APPEND FENNEC_SHARED_LIBRARIES ${ARGN})
endmacro()
macro(fennec_add_compile_options)
list(APPEND FENNEC_PRIVATE_COMPILE_OPTIONS ${ARGN})
endmacro()
macro(fennec_add_link_options)
list(APPEND FENNEC_PRIVATE_LINK_OPTIONS ${ARGN})
endmacro()
@@ -76,12 +80,9 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${FENNEC_SOURCE_DIR}/lib/${FENNEC_BUILD_NAME}
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${FENNEC_SOURCE_DIR}/lib/${FENNEC_BUILD_NAME})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${FENNEC_SOURCE_DIR}/bin/${FENNEC_BUILD_NAME})
# add the test suite as a sub-project
add_subdirectory(test)
add_library(fennec STATIC
# CORE =================================================================================================================
# Core Files
fennec_add_sources(
# CORE =================================================================================================================
include/fennec/core/engine.h source/core/engine.cpp
include/fennec/core/event.h source/core/event.cpp
include/fennec/core/logger.h source/core/logger.cpp
@@ -90,7 +91,7 @@ add_library(fennec STATIC
include/fennec/core/system.h
# SCENE ================================================================================================================
# SCENE ================================================================================================================
include/fennec/scene/scene.h source/scene/scene.cpp
include/fennec/scene/component.h
include/fennec/scene/scene_node.h
@@ -99,7 +100,7 @@ add_library(fennec STATIC
# RENDERERS ============================================================================================================
# RENDERERS ============================================================================================================
include/fennec/renderers/interface/forward.h
include/fennec/renderers/interface/gfxcontext.h
@@ -107,7 +108,7 @@ add_library(fennec STATIC
include/fennec/renderers/interface/gfxresourcepool.h
# CONTAINERS ===========================================================================================================
# CONTAINERS ===========================================================================================================
include/fennec/containers/containers.h
include/fennec/containers/array.h
@@ -135,7 +136,7 @@ add_library(fennec STATIC
include/fennec/containers/detail/_tuple.h
# lang =================================================================================================================
# lang =================================================================================================================
include/fennec/lang/lang.h
include/fennec/lang/metaprogramming.h
@@ -172,7 +173,7 @@ add_library(fennec STATIC
include/fennec/lang/detail/_type_sequences.h
# RTTI =================================================================================================================
# RTTI =================================================================================================================
include/fennec/rtti/typeid.h
include/fennec/rtti/type_data.h
include/fennec/rtti/type.h
@@ -189,7 +190,7 @@ add_library(fennec STATIC
include/fennec/rtti/detail/_type_name.h
# MEMORY ===============================================================================================================
# MEMORY ===============================================================================================================
include/fennec/memory/new.h source/memory/new.cpp
include/fennec/memory/allocator.h
@@ -201,11 +202,11 @@ add_library(fennec STATIC
include/fennec/memory/detail/_ptr_traits.h
# DEBUG ================================================================================================================
# DEBUG ================================================================================================================
source/debug/assert_impl.cpp
# MATH =================================================================================================================
# MATH =================================================================================================================
include/fennec/math/math.h
include/fennec/math/scalar.h
@@ -230,6 +231,7 @@ add_library(fennec STATIC
include/fennec/math/ext/constants.h
include/fennec/math/ext/primes.h
include/fennec/math/ext/quaternion.h
include/fennec/math/ext/rect.h
include/fennec/math/ext/transform.h
@@ -241,7 +243,7 @@ add_library(fennec STATIC
# string ===============================================================================================================
# string ===============================================================================================================
include/fennec/string/locale.h
include/fennec/string/cstring.h
include/fennec/string/string.h
@@ -250,7 +252,7 @@ add_library(fennec STATIC
# format ===============================================================================================================
# format ===============================================================================================================
include/fennec/format/format.h
include/fennec/format/format_arg.h
include/fennec/format/formatter.h
@@ -262,46 +264,55 @@ add_library(fennec STATIC
# filesystem ===========================================================================================================
# filesystem ===========================================================================================================
include/fennec/filesystem/file.h source/filesystem/file.cpp
include/fennec/filesystem/path.h source/filesystem/path.cpp
# interpret ============================================================================================================
# interpret ============================================================================================================
include/fennec/interpret/tokenizer.h
# PLATFORM =============================================================================================================
# PLATFORM =============================================================================================================
include/fennec/platform/interface/fwd.h
include/fennec/platform/interface/display_server.h
include/fennec/platform/interface/platform.h source/platform/interface/platform.cpp
include/fennec/platform/interface/window.h source/platform/interface/window.cpp
# GRAPHICS =============================================================================================================
# GRAPHICS =============================================================================================================
include/fennec/gfx3d/mesh_instance.h
)
# EXTRA SOURCES ========================================================================================================
# add the test suite as a sub-project
add_subdirectory(test)
${FENNEC_EXTRA_SOURCES}
include/fennec/math/ext/rect.h
include/fennec/platform/opengl/egl/error.h
add_library(fennec STATIC
${FENNEC_SOURCES}
include/fennec/platform/window_manager.h
include/fennec/platform/window_manager.cpp
include/fennec/platform/window_manager.h
include/fennec/lang/function.h
include/fennec/threading/thread.h
include/fennec/threading/detail/_thread.h
include/fennec/lang/detail/_function.h
include/fennec/threading/atomic.h
)
add_dependencies(fennec metaprogramming fennec-dependencies)
target_compile_definitions(fennec PUBLIC
${FENNEC_COMPILE_DEFINITIONS}
)
target_compile_definitions(fennec PUBLIC ${FENNEC_COMPILE_DEFINITIONS})
target_compile_options(fennec PRIVATE ${FENNEC_PRIVATE_COMPILE_OPTIONS})
target_link_options(fennec PRIVATE ${FENNEC_PRIVATE_LINK_OPTIONS}) # Do not compile base fennec library with c++ stdlib
# Do not compile base fennec library with c++ stdlib
# fennec does not use the C++ stdlib because it is bloated, difficult to read, and implementation defined.
# This implementation is designed to be as readable as possible, and expose information that would otherwise be obfuscated
target_link_options(fennec PRIVATE ${FENNEC_PRIVATE_LINK_OPTIONS})
target_link_libraries(fennec PRIVATE
${FENNEC_LINK_LIBRARIES}

View File

@@ -20,7 +20,9 @@
add_compile_options("-Wall" "-Wextra" "-pedantic" "-Werror" "-fms-extensions")
fennec_add_link_options("-nostdlib" "-fno-exceptions" "-fno-rtti" "-fdiagnostics-all-candidates")
fennec_add_compile_options("-ffile-prefix-map=${FENNEC_SOURCE_DIR}=.")
fennec_add_link_options("-nostdlib" "-fno-exceptions" "-fno-rtti" "-fdiagnostics-all-candidates" "-pthread")
fennec_add_definitions(
_GLIBCXX_INCLUDE_NEXT_C_HEADERS=1

View File

@@ -26,6 +26,7 @@ if(FENNEC_GRAPHICS_WANT_EGL)
fennec_add_sources(
include/fennec/platform/opengl/egl/fwd.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
)

View File

@@ -392,10 +392,10 @@ public:
constexpr void clear() {
size_t i = _root;
while (i != npos) {
fennec::destruct(_table[i]);
fennec::destruct(&_table[i]);
i = this->_next(i);
}
_table.deallocate(_table);
_table.deallocate();
}
/// @}

View File

@@ -52,6 +52,9 @@ public:
using table_t = dynarray<elem_t, AllocT>;
using freed_t = list<size_t, AllocT>;
class iterator;
class const_iterator;
// Constructors & Destructor ===========================================================================================
@@ -189,6 +192,135 @@ public:
/// @}
// Iterator ============================================================================================================
iterator begin() {
return iterator(this, 0);
}
iterator end() {
return iterator(this, _size);
}
const_iterator begin() const {
return iterator(this, 0);
}
const_iterator end() const {
return iterator(this, _size);
}
class iterator {
public:
iterator(object_pool* pool, size_t start)
: pool(pool), curr(start) {
_fix();
}
iterator(const iterator&) = default;
iterator(iterator&&) noexcept = default;
~iterator() = default;
iterator& operator=(const iterator&) = default;
iterator& operator=(iterator&&) noexcept = default;
iterator operator++(int) {
iterator ret = *this;
++curr;
_fix();
return ret;
}
iterator& operator++() {
++curr;
_fix();
return *this;
}
value_t& operator*() const {
return *pool->_table[curr];
}
value_t* operator->() const {
return *pool->_table[curr];
}
bool operator==(const iterator& it) {
return pool == it.pool and curr == it.curr;
}
bool operator!=(const iterator& it) {
return pool != it.pool or curr != it.curr;
}
private:
object_pool* pool;
size_t curr;
void _fix() {
while (curr < pool->_size and not pool->_table[curr]) {
++curr;
}
}
};
class const_iterator {
public:
const_iterator(const object_pool* pool, size_t start)
: pool(pool), curr(start) {
_fix();
}
const_iterator(const const_iterator&) = default;
const_iterator(const_iterator&&) noexcept = default;
~const_iterator() = default;
const_iterator& operator=(const const_iterator&) = default;
const_iterator& operator=(const_iterator&&) noexcept = default;
const_iterator operator++(int) {
const_iterator ret = *this;
++curr;
_fix();
return ret;
}
const_iterator& operator++() {
++curr;
_fix();
return *this;
}
const value_t& operator*() const {
return *pool->_table[curr];
}
const value_t* operator->() const {
return *pool->_table[curr];
}
bool operator==(const const_iterator& it) {
return pool == it.pool and curr == it.curr;
}
bool operator!=(const const_iterator& it) {
return pool != it.pool or curr != it.curr;
}
private:
const object_pool* pool;
size_t curr;
void _fix() {
while (curr < pool->_size and not pool->_table[curr]) {
++curr;
}
}
};
private:
table_t _table;
freed_t _freed;

View File

@@ -46,7 +46,7 @@ public:
static void log(const cstring& str,
uint32_t _line = FENNEC_BUILTIN_LINE(),
const char* const _file = FENNEC_BUILTIN_FILE()
const char* _file = FENNEC_BUILTIN_FILE()
) {
logger& inst = instance();
@@ -63,7 +63,7 @@ public:
static void log(const string& str,
uint32_t _line = FENNEC_BUILTIN_LINE(),
const char* const _file = FENNEC_BUILTIN_FILE()
const char* _file = FENNEC_BUILTIN_FILE()
) {
logger& inst = instance();

View File

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

View File

@@ -55,6 +55,12 @@ namespace fennec::detail
template<> struct _is_integral<llong_t> : true_type {};
template<> struct _is_integral<ullong_t> : true_type {};
template<typename> struct _is_const : false_type {};
template<typename T> struct _is_const<const T> : true_type {};
template<typename> struct _is_volatile : false_type {};
template<typename T> struct _is_volatile<volatile T> : true_type {};
// Most unsigned types will underflow `-1` to the types maximum value
template<typename TypeT> struct _is_signed : bool_constant<TypeT(-1) < TypeT(0)> {};
template<typename TypeT> struct _is_unsigned : bool_constant<TypeT(-1) >= TypeT(0)> {};

View File

@@ -20,9 +20,39 @@
#define FENNEC_LANG_DETAIL_TYPE_TRANSFORMS_H
#include <fennec/lang/types.h>
#include <fennec/lang/detail/_type_traits.h>
namespace fennec::detail
{
template<typename TypeT> struct _add_pointer : type_identity<TypeT*> {};
template<typename TypeT> struct _remove_pointer : type_identity<TypeT> {};
template<typename TypeT> struct _remove_pointer<TypeT*> : type_identity<TypeT> {};
template<typename TypeT> struct _add_const : type_identity<const TypeT> {};
template<typename TypeT> struct _remove_const : type_identity<TypeT> {};
template<typename TypeT> struct _remove_const<const TypeT> : type_identity<TypeT> {};
template<typename TypeT> struct _add_volatile : type_identity<volatile TypeT> {};
template<typename TypeT> struct _remove_volatile : type_identity<TypeT> {};
template<typename TypeT> struct _remove_volatile<volatile TypeT> : type_identity<TypeT> {};
template<typename TypeT> struct _add_cv : _add_const<typename _add_volatile<TypeT>::type> {};
template<typename TypeT> struct _remove_cv : type_identity<TypeT> {};
template<typename TypeT> struct _remove_cv<const TypeT> : type_identity<TypeT> {};
template<typename TypeT> struct _remove_cv<volatile TypeT> : type_identity<TypeT> {};
template<typename TypeT> struct _remove_cv<const volatile TypeT> : type_identity<TypeT> {};
template<typename TypeT>
struct _decay : conditional<_is_const<const TypeT>{}, _remove_cv<TypeT>, _add_pointer<TypeT>> {};
template<typename TypeT> requires requires { typename TypeT::element_t; }
struct _decay<TypeT> : type_identity<typename TypeT::decay_t> {};
template<typename TypeT, size_t N>
struct _decay<TypeT[N]> : type_identity<TypeT*> {};
template<typename TypeT>
struct _decay<TypeT[]> : type_identity<TypeT*> {};
template<typename _Tp, typename = void>
struct _add_lvalue_reference {

View File

@@ -0,0 +1,87 @@
// =====================================================================================================================
// 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 function.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_LANG_FUNCTION_H
#define FENNEC_LANG_FUNCTION_H
#include <fennec/lang/types.h>
#include <fennec/lang/assert.h>
#include <fennec/lang/utility.h>
#include <fennec/lang/detail/_function.h>
namespace fennec
{
template<typename> class function;
template<typename ReturnT, typename...ArgsT>
class function<ReturnT(ArgsT...)> {
public:
constexpr function() noexcept = default;
constexpr ~function() = default;
constexpr function(const function&) noexcept = default;
constexpr function( function&&) noexcept = default;
constexpr function(ReturnT (*func)(ArgsT...))
: call(func) {
}
constexpr function(nullptr_t) noexcept : function() {}
constexpr function& operator=(const function&) = default;
constexpr function& operator=(function&&) = default;
constexpr function& operator=(nullptr_t) {
call = nullptr;
return *this;
}
constexpr function& operator=(ReturnT (*func)(ArgsT...)) {
call = func;
return *this;
}
constexpr operator bool() const noexcept { return call != nullptr; }
ReturnT operator()(ArgsT...args) const noexcept {
assertf(call != nullptr, "Attempted to call a null function object!");
return call(fennec::forward<ArgsT>(args)...);
}
private:
ReturnT (*call)(ArgsT&&...) { nullptr };
};
}
#endif // FENNEC_LANG_FUNCTION_H

View File

@@ -21,6 +21,7 @@
#include <fennec/lang/types.h>
#include <fennec/lang/type_traits.h>
#include <fennec/lang/bits.h>
namespace fennec
{

View File

@@ -176,6 +176,27 @@
# define FENNEC_HAS_BUILTIN_IS_CLASS
#endif
#if __has_builtin(__is_member_pointer)
# define FENNEC_HAS_BUILTIN_IS_MEMBER_POINTER 1
# define FENNEC_BUILTIN_IS_MEMBER_POINTER(arg) __is_member_pointer(arg)
#else
# define FENNEC_HAS_BUILTIN_IS_MEMBER_POINTER 0
#endif
#if __has_builtin(__is_member_function_pointer)
# define FENNEC_HAS_BUILTIN_IS_MEMBER_FUNCTION_POINTER 1
# define FENNEC_BUILTIN_IS_MEMBER_FUNCTION_POINTER(arg) __is_member_function_pointer(arg)
#else
# define FENNEC_HAS_BUILTIN_IS_MEMBER_FUNCTION_POINTER 0
#endif
#if __has_builtin(__is_member_object_pointer)
# define FENNEC_HAS_BUILTIN_IS_MEMBER_OBJECT_POINTER 1
# define FENNEC_BUILTIN_IS_MEMBER_OBJECT_POINTER(arg) __is_member_object_pointer(arg)
#else
# define FENNEC_HAS_BUILTIN_IS_MEMBER_OBJECT_POINTER 0
#endif
// CONSTRUCTORS ========================================================================================================
@@ -214,6 +235,38 @@
# define FENNEC_HAS_BUILTIN_IS_ASSIGNABLE 0
#endif
// Inconsistent without intrinsics
#if __has_builtin(__is_trivial)
# define FENNEC_HAS_BUILTIN_IS_TRIVIAL 1
# define FENNEC_BUILTIN_IS_TRIVIAL(a) __is_trivial(a)
#else
# define FENNEC_HAS_BUILTIN_IS_TRIVIAL 0
#endif
// Difficult and Inconsistent without intrinsics
#if __has_builtin(__is_trivially_copyable)
# define FENNEC_HAS_BUILTIN_IS_TRIVIALLY_COPYABLE 1
# define FENNEC_BUILTIN_IS_TRIVIALLY_COPYABLE(a) __is_trivially_copyable(a)
#else
# define FENNEC_HAS_BUILTIN_IS_TRIVIALLY_COPYABLE 0
#endif
// Impossible without instrinsics
#if __has_builtin(__is_standard_layout)
# define FENNEC_HAS_BUILTIN_IS_STANDARD_LAYOUT 1
# define FENNEC_BUILTIN_IS_STANDARD_LAYOUT(arg) __is_standard_layout(arg)
#else
# define FENNEC_HAS_BUILTIN_IS_STANDARD_LAYOUT 0
#endif
// Impossible without instrinsics
#if __has_builtin(__has_unique_object_representations)
# define FENNEC_HAS_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS 1
# define FENNEC_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS(arg) __has_unique_object_representations(arg)
#else
# define FENNEC_HAS_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS 0
#endif
// Type Traits
// can_convert is also very difficult to implement without intrinsics
@@ -264,6 +317,22 @@
# define FENNEC_HAS_BUILTIN_IS_FINAL 0
#endif
// Inconsistent without intrinsics
#if __has_builtin(__is_aggregate)
# define FENNEC_HAS_BUILTIN_IS_AGGREGATE 1
# define FENNEC_BUILTIN_IS_AGGREGATE(arg) __is_aggregate(arg)
#else
# define FENNEC_HAS_BUILTIN_IS_AGGREGATE 0
#endif
// Inconsistent without intrinsics
#if __has_builtin(__builtin_is_implicit_lifetime)
# define FENNEC_HAS_BUILTIN_IS_IMPLICIT_LIFETIME 1
# define FENNEC_BUILTIN_IS_IMPLICIT_LIFETIME(arg) __builtin_is_implicit_lifetime(arg)
#else
# define FENNEC_HAS_BUILTIN_IS_IMPLICIT_LIFETIME 0
#endif
// Inconsistent without intrinsics
#if __has_builtin(__is_function)
# define FENNEC_HAS_BUILTIN_IS_FUNCTION 1
@@ -288,14 +357,6 @@
# define FENNEC_HAS_BUILTIN_IS_POLYMORPHIC 0
#endif
// Impossible without instrinsics
#if __has_builtin(__is_standard_layout)
# define FENNEC_HAS_BUILTIN_IS_STANDARD_LAYOUT 1
# define FENNEC_BUILTIN_IS_STANDARD_LAYOUT(arg) __is_standard_layout(arg)
#else
# define FENNEC_HAS_BUILTIN_IS_STANDARD_LAYOUT 0
#endif
// For compilers without or differently named builtins
#else

View File

@@ -147,18 +147,18 @@
/// <th style="vertical-align: top">Description
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_fundamental "is_fundamental<TypeT>::value"<br>
/// \ref fennec::is_fundamental_v "is_fundamental_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_fundamental
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_arithmetic "is_arithmetic<TypeT>::value"<br>
/// \ref fennec::is_arithmetic_v "is_arithmetic_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_arithmetic
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_fundamental "is_fundamental<TypeT>::value"<br>
/// \ref fennec::is_fundamental_v "is_fundamental_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_fundamental
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_scalar "is_scalar<TypeT>::value"<br>
/// \ref fennec::is_scalar_v "is_scalar_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
@@ -271,12 +271,6 @@
/// \copydetails fennec::is_aggregate
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_implicit_lifetime "is_implicit_lifetime<TypeT>::value"<br>
/// \ref fennec::is_implicit_lifetime_v "is_implicit_lifetime_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
/// \copydetails fennec::is_implicit_lifetime
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
/// \ref fennec::is_signed "is_signed<TypeT>::value"<br>
/// \ref fennec::is_signed_v "is_signed_v<TypeT>"
/// <td width="50%" style="vertical-align: top">
@@ -451,7 +445,7 @@ constexpr inline bool is_constant_evaluated() noexcept {
/// \details Stores a boolean value in `is_void::value`, representing whether the provided type is of base type void.
/// \tparam T type to check
template<typename T> struct is_void
: detail::_is_void<remove_cvr_t<T>>{};
: detail::_is_void<remove_cvref_t<T>>{};
///
/// \brief Shorthand for ```is_void<T>::value```
@@ -468,7 +462,7 @@ template<typename T> constexpr bool_t is_void_v = is_void<T>::value;
/// \details Stores a boolean value in `is_null_pointer::value`, representing whether the provided type is of base type nullptr_t.
/// \tparam T type to check
template<typename T> struct is_null_pointer
: detail::_is_null_pointer<remove_cvr_t<T>>{};
: detail::_is_null_pointer<remove_cvref_t<T>>{};
///
/// \brief Shorthand for ```is_null_pointer<T>::value```
@@ -477,6 +471,57 @@ template<typename T> constexpr bool_t is_null_pointer_v = is_null_pointer<T>::va
// fennec::is_bool =====================================================================================================
///
/// \brief Check if \p T is of type bool
///
/// \details Stores a boolean value in `is_bool::value`, representing whether the provided type is of base type bool.
/// \tparam T type to check
template<typename T> struct is_bool
: detail::_is_bool<remove_cvref_t<T>>{};
///
/// \brief Shorthand for ```is_bool<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_bool_v = is_bool<T>::value;
// fennec::is_integral =================================================================================================
///
/// \brief Check if \p T is of an integral
///
/// \details Stores a boolean value in `is_integral::value`, representing whether the provided type is of a base integer type.
/// \tparam T type to check
template<typename T> struct is_integral
: detail::_is_integral<remove_cvref_t<T>> {};
///
/// \brief Shorthand for ```is_integral<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_integral_v = is_integral<T>::value;
// fennec::is_floating_point ===========================================================================================
///
/// \brief Check if \p T is of a floating point type
///
/// \details Stores a boolean value in `is_floating_point::value`, representing whether the provided type is of a base floating point type.
/// \tparam T type to check
template<typename T> struct is_floating_point
: detail::_is_floating_point<remove_cvref_t<T>>{};
///
/// \brief Shorthand for ```is_floating_point<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_floating_point_v = is_floating_point<T> {};
// fennec::is_array ====================================================================================================
#ifdef FENNEC_BUILTIN_IS_ARRAY
@@ -557,7 +602,7 @@ template<typename T> constexpr size_t is_class_v = is_class<T>::value;
// fennec::is_function ====================================================================================================
// fennec::is_function =================================================================================================
///
/// \brief Check if \p T is a class
@@ -572,41 +617,363 @@ template<typename T> constexpr size_t is_function_v = is_function<T>::value;
// Integral Types ======================================================================================================
// fennec::is_bool =====================================================================================================
// fennec::is_pointer ==================================================================================================
///
/// \brief Check if \p T is of type bool
/// \brief Check if \p T is of a pointer type
///
/// \details Stores a boolean value in `is_bool::value`, representing whether the provided type is of base type bool.
/// \details Stores a boolean value in `is_pointer::value`, representing whether the provided type is of a base pointer type.
/// \tparam T type to check
template<typename T> struct is_bool
: detail::_is_bool<remove_cvr_t<T>>{};
template<typename T> struct is_pointer
: detail::_is_pointer<remove_cvref_t<T>>{};
///
/// \brief Shorthand for ```is_bool<T>::value```
/// \brief Shorthand for ```is_pointer<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_bool_v = is_bool<T>::value;
template<typename T> constexpr bool_t is_pointer_v = is_pointer<T> {};
// fennec::is_integral =================================================================================================
// fennec::is_lvalue_reference =========================================================================================
///
/// \brief Check if \p T is of an integral
/// \brief Check if \p T is of a floating point type
///
/// \details Stores a boolean value in `is_integral::value`, representing whether the provided type is of a base integer type.
/// \details Checks if type `T` is a floating point type and store it in `is_same::value`.
/// \tparam T type to check
template<typename T> struct is_integral
: detail::_is_integral<remove_cvr_t<T>> {};
template<typename T> struct is_lvalue_reference
: detail::_is_lvalue_reference<T>{};
///
/// \brief Shorthand for ```is_integral<T>::value```
/// \brief Shorthand for ```is_floating_point<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_integral_v = is_integral<T>::value;
template<typename T> constexpr bool_t is_lvalue_reference_v = is_lvalue_reference<T> {};
// fennec::is_rvalue_reference =========================================================================================
///
/// \brief Check if \p T is of a floating point type
///
/// \details Checks if type `T` is a floating point type and store it in `is_same::value`.
/// \tparam T type to check
template<typename T> struct is_rvalue_reference
: detail::_is_rvalue_reference<T>{};
///
/// \brief Shorthand for ```is_floating_point<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_rvalue_reference_v = is_rvalue_reference<T> {};
// fennec::is_member_function_pointer ==================================================================================
///
/// \brief Check if \p T is a pointer to a member function
///
/// \details Checks if type `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```
/// \tparam T type to check
template<typename T> constexpr bool_t is_member_function_pointer_v = is_member_function_pointer<T> {};
// fennec::is_member_object_pointer ====================================================================================
///
/// \brief Check if \p T is a pointer to a member object
///
/// \details Checks if type `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```
/// \tparam T type to check
template<typename T> constexpr bool_t is_member_object_pointer_v = is_member_object_pointer<T> {};
// fennec::is_arithmetic ===============================================================================================
///
/// \brief Check if \p T is an arithmetic type
///
/// \details Checks if type `T` is a built-in type with arithmetic operators and store it in `is_same::value`.
/// \tparam T type to check
template<typename T> struct is_arithmetic
: bool_constant<is_integral_v<T> or is_floating_point_v<T>>{};
///
/// \brief Shorthand for ```is_arithmetic<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_arithmetic_v = is_arithmetic<T>::value;
// fennec::is_fundamental ==============================================================================================
///
/// \brief Check if \p T is a fundamental type, i.e. arithmetic, void, or nullptr_t
/// \tparam T type to check
template<typename T> struct is_fundamental
: bool_constant<is_arithmetic_v<T> or is_void_v<T> or is_null_pointer_v<T>>{};
///
/// \brief Shorthand for ```is_fundamental<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_fundamental_v = is_fundamental<T>::value;
// fennec::is_scalar ===================================================================================================
///
/// \brief Check if \p T is an arithmetic type
///
/// \details Checks if type `T` is a built-in type with arithmetic operators and store it in `is_same::value`.
/// \tparam T type to check
template<typename T> struct is_scalar
: bool_constant<is_arithmetic_v<T> or is_enum_v<T> or is_pointer_v<T>>{};
///
/// \brief Shorthand for ```is_scalar<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_scalar_v = is_scalar<T>::value;
// fennec::is_object ===================================================================================================
///
/// \brief Check if \p T is an object
///
/// \details Checks if type `T` is an object and store it in `is_same::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```
/// \tparam T type to check
template<typename T> constexpr bool_t is_object_v = is_object<T>::value;
// fennec::is_compound =================================================================================================
///
/// \brief Check if \p T is a object compound type
///
/// \details Checks if type `T` is an object and store it in `is_same::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```
/// \tparam T type to check
template<typename T> constexpr bool_t is_compound_v = is_compound<T>::value;
// fennec::is_reference ================================================================================================
///
/// \brief Check if \p T is of a floating point type
///
/// \details Checks if type `T` is a floating point type and store it in `is_same::value`.
/// \tparam T type to check
template<typename T> struct is_reference
: detail::_is_reference<T>{};
///
/// \brief Shorthand for ```is_floating_point<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_reference_v = is_reference<T> {};
// fennec::is_member_pointer ===========================================================================================
///
/// \brief Check if \p T is a pointer to a member
///
/// \details Checks if type `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```
/// \tparam T type to check
template<typename T> constexpr bool_t is_member_pointer_v = is_member_pointer<T> {};
// fennec::is_trivial ==================================================================================================
///
/// \brief Check if type `T` is trivial
///
/// \details Checks if `T`
/// \tparam T type to check
template<typename T> struct is_trivial : bool_constant<FENNEC_BUILTIN_IS_TRIVIAL(T)> {};
///
/// \brief Shorthand for `is_trivial<T>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_trivial_v = is_trivial<T>{};
// fennec::is_trivially_copyable =======================================================================================
///
/// \brief Check if type `T` is trivially_copyable
///
/// \details Checks if `T`
/// \tparam T type to check
template<typename T> struct is_trivially_copyable : bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_COPYABLE(T)> {};
///
/// \brief Shorthand for `is_trivially_copyable<T>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_trivially_copyable_v = is_trivially_copyable<T>{};
// fennec::is_standard_layout ==========================================================================================
///
/// \brief Check if type `T` is standard_layout
///
/// \details Checks if `T`
/// \tparam T type to check
template<typename T> struct is_standard_layout : bool_constant<FENNEC_BUILTIN_IS_STANDARD_LAYOUT(T)> {};
///
/// \brief Shorthand for `is_standard_layout<T>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_standard_layout_v = is_standard_layout<T>{};
// fennec::has_unique_object_representations ===========================================================================
///
/// \brief Check if type `T` has unique object representations
///
/// \details Checks if `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>)> {};
///
/// \brief Shorthand for `has_unique_object_representations<T>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t has_unique_object_representations_v = has_unique_object_representations<T>{};
// fennec::is_empty ====================================================================================================
///
/// \brief Check if type `T` is empty
///
/// \details Checks if `T`
/// \tparam T type to check
template<typename T> struct is_empty : bool_constant<FENNEC_BUILTIN_IS_EMPTY(T)> {};
///
/// \brief Shorthand for `is_empty<T>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_empty_v = is_empty<T>{};
// fennec::is_polymorphic ==============================================================================================
///
/// \brief Check if type `T` is polymorphic
///
/// \details Checks if `T`
/// \tparam T type to check
template<typename T> struct is_polymorphic : bool_constant<FENNEC_BUILTIN_IS_POLYMORPHIC(T)> {};
///
/// \brief Shorthand for `is_polymorphic<T>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_polymorphic_v = is_polymorphic<T>{};
// fennec::is_abstract =================================================================================================
///
/// \brief Check if type `T` is abstract
///
/// \details Checks if `T`
/// \tparam T type to check
template<typename T> struct is_abstract : bool_constant<FENNEC_BUILTIN_IS_ABSTRACT(T)> {};
///
/// \brief Shorthand for `is_abstract<T>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_abstract_v = is_abstract<T>{};
// fennec::is_complete =================================================================================================
///
/// \brief Check if type `T` is complete
///
/// \details Checks if `T`
/// \tparam T type to check
template<typename T> struct is_complete : detail::_is_complete<T>::type {};
///
/// \brief Shorthand for `is_complete<T>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_complete_v = is_complete<T>{};
// fennec::is_final =================================================================================================
///
/// \brief Check if type `T` is final
///
/// \details Checks if `T`
/// \tparam T type to check
template<typename T> struct is_final : bool_constant<FENNEC_BUILTIN_IS_FINAL(T)> {};
///
/// \brief Shorthand for `is_final<T>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_final_v = is_final<T>{};
// fennec::is_aggregate =================================================================================================
///
/// \brief Check if type `T` is aggregate
///
/// \details Checks if `T`
/// \tparam T type to check
template<typename T> struct is_aggregate : bool_constant<FENNEC_BUILTIN_IS_AGGREGATE(T)> {};
///
/// \brief Shorthand for `is_aggregate<T>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_aggregate_v = is_aggregate<T>{};
@@ -619,7 +986,7 @@ template<typename T> constexpr bool_t is_integral_v = is_integral<T>::value;
/// \details Checks if type `T` is a signed type i.e. `T(-1) < T(0)` and stores it in `is_same::value`.
/// \tparam T type to check
template<typename T> struct is_signed
: detail::_is_signed<remove_cvr_t<T>> {};
: detail::_is_signed<remove_cvref_t<T>> {};
///
/// \brief Shorthand for ```is_signed<T>::value```
@@ -637,138 +1004,12 @@ template<typename T> constexpr bool_t is_signed_v = is_signed<T>::value;
/// \details Checks if type `T` is an unsigned type i.e. `T(-1) > T(0)` and stores it in `is_same::value`.
/// \tparam T type to check
template<typename T> struct is_unsigned
: detail::_is_unsigned<remove_cvr_t<T>> {};
: detail::_is_unsigned<remove_cvref_t<T>> {};
///
/// \brief Shorthand for ```is_unsigned<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_unsigned_v = is_unsigned<T>::value;
// Floating Point Types ================================================================================================
///
/// \brief Check if \p T is of a floating point type
///
/// \details Stores a boolean value in `is_floating_point::value`, representing whether the provided type is of a base floating point type.
/// \tparam T type to check
template<typename T> struct is_floating_point
: detail::_is_floating_point<remove_cvr_t<T>>{};
///
/// \brief Shorthand for ```is_floating_point<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_floating_point_v = is_floating_point<T> {};
// Pointer Types =======================================================================================================
///
/// \brief Check if \p T is of a pointer type
///
/// \details Stores a boolean value in `is_pointer::value`, representing whether the provided type is of a base pointer type.
/// \tparam T type to check
template<typename T> struct is_pointer
: detail::_is_pointer<remove_cvr_t<T>>{};
///
/// \brief Shorthand for ```is_pointer<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_pointer_v = is_pointer<T> {};
// Reference Types =======================================================================================================
///
/// \brief Check if \p T is of a floating point type
///
/// \details Checks if type `T` is a floating point type and store it in `is_same::value`.
/// \tparam T type to check
template<typename T> struct is_reference
: detail::_is_reference<T>{};
///
/// \brief Shorthand for ```is_floating_point<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_reference_v = is_reference<T> {};
///
/// \brief Check if \p T is of a floating point type
///
/// \details Checks if type `T` is a floating point type and store it in `is_same::value`.
/// \tparam T type to check
template<typename T> struct is_lvalue_reference
: detail::_is_lvalue_reference<T>{};
///
/// \brief Shorthand for ```is_floating_point<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_lvalue_reference_v = is_lvalue_reference<T> {};
///
/// \brief Check if \p T is of a floating point type
///
/// \details Checks if type `T` is a floating point type and store it in `is_same::value`.
/// \tparam T type to check
template<typename T> struct is_rvalue_reference
: detail::_is_rvalue_reference<T>{};
///
/// \brief Shorthand for ```is_floating_point<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_rvalue_reference_v = is_rvalue_reference<T> {};
// Arithmetic Types ====================================================================================================
///
/// \brief Check if \p T is an arithmetic type
///
/// \details Checks if type `T` is a built-in type with arithmetic operators and store it in `is_same::value`.
/// \tparam T type to check
template<typename T> struct is_arithmetic
: bool_constant<is_integral_v<T> or is_floating_point_v<T>>{};
///
/// \brief Shorthand for ```is_arithmetic<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_arithmetic_v = is_arithmetic<T>::value;
// Arithmetic Types ====================================================================================================
///
/// \brief Check if \p T is an arithmetic type
///
/// \details Checks if type `T` is a built-in type with arithmetic operators and store it in `is_same::value`.
/// \tparam T type to check
template<typename T> struct is_scalar
: bool_constant<is_arithmetic_v<T> or is_enum_v<T> or is_pointer_v<T>>{};
///
/// \brief Shorthand for ```is_scalar<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_scalar_v = is_scalar<T>::value;
// fennec::is_fundamental ==============================================================================================
///
/// \brief Check if \p T is a fundamental type, i.e. arithmetic, void, or nullptr_t
/// \tparam T type to check
template<typename T> struct is_fundamental
: bool_constant<is_arithmetic_v<T> || is_void_v<T> || is_null_pointer_v<T>>{};
///
/// \brief Shorthand for ```is_fundamental<T>::value```
/// \tparam T type to check
template<typename T> constexpr bool_t is_fundamental_v = is_fundamental<T>::value;
template<typename T> constexpr bool_t is_unsigned_v = is_unsigned<T>::value;
// fennec::is_same =====================================================================================================
@@ -791,7 +1032,7 @@ template<typename T> struct is_same<T, T> : true_type {};
template<typename T0, typename T1> constexpr bool_t is_same_v = is_same<T0, T1> {};
// fennec::is_base_of =====================================================================================================
// fennec::is_base_of ==================================================================================================
///
/// \brief Check if `Derived` has a base type of `Base`
@@ -809,61 +1050,7 @@ template<typename Base, typename Derived> struct is_base_of : bool_constant<
/// \tparam Derived derived type to check
template<typename Base, typename Derived> constexpr bool_t is_base_of_v = is_base_of<Base, Derived> {};
// fennec::is_complete ==============================================================================================
///
/// \brief Check if type `T` is complete
///
/// \details Checks if `T`
/// \tparam T type to check
template<typename T> struct is_complete : detail::_is_complete<T>::type {};
///
/// \brief Shorthand for `is_complete<TypeT0, TypeT1>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_complete_v = is_complete<T>{};
// fennec::is_iterable ==============================================================================================
///
/// \brief Check if type `T` is iterable
///
/// \details Checks if `T`
/// \tparam T type to check
template<typename T> struct is_iterable : decltype(detail::_is_iterable<T>(0)) {};
///
/// \brief Shorthand for `is_iterable<TypeT0, TypeT1>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_iterable_v = is_iterable<T>{};
// fennec::is_indexable ==============================================================================================
///
/// \brief Check if type `T` is indexable
///
/// \details Checks if `T`
/// \tparam T type to check
template<typename T> struct is_indexable : decltype(detail::_is_indexable<T>(0)) {};
///
/// \brief Shorthand for `is_indexable<TypeT0, TypeT1>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_indexable_v = is_indexable<T>{};
// fennec::is_mappable ==============================================================================================
///
/// \brief Check if type `T` is mappable
///
/// \details Checks if `T`
/// \tparam T type to check
template<typename T> struct is_mappable : decltype(detail::_is_mappable<T>(0)) {};
///
/// \brief Shorthand for `is_mappable<TypeT0, TypeT1>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_mappable_v = is_mappable<T>{};
// fennec::is_convertible ==============================================================================================
@@ -883,6 +1070,7 @@ template<typename FromT, typename ToT> struct is_convertible
template<typename FromT, typename ToT> constexpr bool_t is_convertible_v = is_convertible<FromT, ToT>{};
// fennec::is_constructible ============================================================================================
///
@@ -899,6 +1087,8 @@ template<typename ClassT, typename...ArgsT> constexpr bool_t is_constructible_v
// fennec::is_trivially_constructible ==================================================================================
///
/// \brief Check if `ClassT` is trivially constructible
/// \tparam ClassT The class type to test
@@ -911,6 +1101,8 @@ template<typename ClassT> constexpr bool_t is_trivially_constructible_v = is_tri
// fennec::is_default_constructible ====================================================================================
///
/// \brief Check if `ClassT` is default constructible
/// \tparam ClassT The class type to test
@@ -923,6 +1115,8 @@ template<typename ClassT> constexpr bool_t is_default_constructible_v = is_defau
// fennec::is_copy_constructible =======================================================================================
///
/// \brief Check if `ClassT` is copy constructible
/// \tparam ClassT The class type to test
@@ -935,8 +1129,10 @@ template<typename ClassT, typename...ArgsT> constexpr bool_t is_copy_constructib
// fennec::is_move_constructible =======================================================================================
///
/// \brief Check if `ClassT` is copy constructible
/// \brief Check if `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>)> {};
@@ -946,42 +1142,6 @@ template<typename ClassT> struct is_move_constructible
template<typename ClassT, typename...ArgsT> constexpr bool_t is_move_constructible_v = is_move_constructible<ClassT>{};
// fennec::is_destructible ===================================================================================
///
/// \brief Check if `ClassT` is destructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_destructible
: detail::_is_destructible<ClassT>::type {};
///
/// \brief Shorthand for `is_destructible<ClassT, ArgsT...>::value`
template<typename ClassT> constexpr bool_t is_destructible_v = is_destructible<ClassT>{};
///
/// \brief Check if `ClassT` is trivially destructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_trivially_destructible
: bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE(ClassT)> {};
///
/// \brief Shorthand for `is_trivially_destructible<ClassT, ArgsT...>::value`
template<typename ClassT> constexpr bool_t is_trivially_destructible_v = is_trivially_destructible<ClassT>{};
///
/// \brief Check if `ClassT` is nothrow destructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_nothrow_destructible
: detail::_is_nothrow_destructible<ClassT>::type {};
///
/// \brief Shorthand for `is_nothrow_destructible<ClassT, ArgsT...>::value`
template<typename ClassT> constexpr bool_t is_nothrow_destructible_v = is_nothrow_destructible<ClassT>{};
// fennec::is_assignable ===============================================================================================
@@ -998,6 +1158,7 @@ template<typename ClassAT, typename ClassBT> struct is_assignable
template<typename ClassT, typename...ArgsT> constexpr bool_t is_assignable_v = is_assignable<ClassT, ArgsT...>{};
// fennec::is_copy_assignable ==========================================================================================
///
@@ -1011,6 +1172,7 @@ template<typename ClassT> struct is_copy_assignable
template<typename ClassT> constexpr bool_t is_copy_assignable_v = is_copy_assignable<ClassT>{};
// fennec::is_move_assignable ==========================================================================================
///
@@ -1024,6 +1186,96 @@ template<typename ClassT> struct is_move_assignable
template<typename ClassT> constexpr bool_t is_move_assignable_v = is_move_assignable<ClassT>{};
// fennec::is_destructible =============================================================================================
///
/// \brief Check if `ClassT` is destructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_destructible
: detail::_is_destructible<ClassT>::type {};
///
/// \brief Shorthand for `is_destructible<ClassT, ArgsT...>::value`
template<typename ClassT> constexpr bool_t is_destructible_v = is_destructible<ClassT>{};
// fennec::is_trivially_destructible ===================================================================================
///
/// \brief Check if `ClassT` is trivially destructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_trivially_destructible
: bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE(ClassT)> {};
///
/// \brief Shorthand for `is_trivially_destructible<ClassT, ArgsT...>::value`
template<typename ClassT> constexpr bool_t is_trivially_destructible_v = is_trivially_destructible<ClassT>{};
// fennec::is_nothrow_destructible =====================================================================================
///
/// \brief Check if `ClassT` is nothrow destructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_nothrow_destructible
: detail::_is_nothrow_destructible<ClassT>::type {};
///
/// \brief Shorthand for `is_nothrow_destructible<ClassT, ArgsT...>::value`
template<typename ClassT> constexpr bool_t is_nothrow_destructible_v = is_nothrow_destructible<ClassT>{};
// fennec::is_iterable =================================================================================================
///
/// \brief Check if type `T` is iterable
///
/// \details Checks if `T`
/// \tparam T type to check
template<typename T> struct is_iterable : decltype(detail::_is_iterable<T>(0)) {};
///
/// \brief Shorthand for `is_iterable<TypeT0, TypeT1>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_iterable_v = is_iterable<T>{};
// fennec::is_indexable ================================================================================================
///
/// \brief Check if type `T` is indexable
///
/// \details Checks if `T`
/// \tparam T type to check
template<typename T> struct is_indexable : decltype(detail::_is_indexable<T>(0)) {};
///
/// \brief Shorthand for `is_indexable<TypeT0, TypeT1>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_indexable_v = is_indexable<T>{};
// fennec::is_mappable =================================================================================================
///
/// \brief Check if type `T` is mappable
///
/// \details Checks if `T`
/// \tparam T type to check
template<typename T> struct is_mappable : decltype(detail::_is_mappable<T>(0)) {};
///
/// \brief Shorthand for `is_mappable<TypeT0, TypeT1>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_mappable_v = is_mappable<T>{};
}
#endif // FENNEC_LANG_TYPE_TRAITS_H

View File

@@ -127,6 +127,12 @@
namespace fennec
{
// Decay Conversions ===================================================================================================
template<typename T> struct decay : detail::_decay<T> {};
template<typename T> using decay_t = typename decay<T>::type;
// Pointer Conversions =================================================================================================
///
@@ -134,7 +140,7 @@ namespace fennec
///
/// \details adds a pointer to the provided type such that `T` becomes `T*`
/// \tparam T Resultant Type
template<typename T> struct add_pointer : type_identity<T*>{};
template<typename T> struct add_pointer : detail::_add_pointer<T>{};
///
/// \brief shorthand for `typename add_pointer<T>::type`
@@ -146,10 +152,7 @@ template<typename T> using add_pointer_t = typename add_pointer<T>::type;
///
/// \details removes a pointer from the provided type such that `T*` becomes `T`
/// \tparam T Resultant Type
template<typename T> struct remove_pointer : type_identity<T> {};
// specialization for T*
template<typename T> struct remove_pointer<T*> : type_identity<T> {};
template<typename T> struct remove_pointer : detail::_remove_pointer<T> {};
///
/// \brief shorthand for `typename remove_pointer<T>::type`
@@ -235,30 +238,24 @@ template<typename T> using add_rvalue_reference_t = typename add_rvalue_referen
///
/// \details adds const qualification to the provided type such that `T` becomes `const T`
/// \tparam T Reference Type
template<typename T> struct add_const : type_identity<const T> {};
template<typename T> struct add_const : detail::_add_const<T> {};
///
/// \brief shorthand for `typename add_const<T>::type`
template<typename T> using add_const_t = typename add_const<T>::type;
// specialization for const types
template<typename T> struct add_const<const T> : type_identity<const T> {};
///
/// \brief remove the const qualifier from the provided type \p T
///
/// \details removes const qualification from the provided type such that `const T` becomes `T`
/// \tparam T Reference Type
template<typename T> struct remove_const : type_identity<T> {};
template<typename T> struct remove_const : detail::_remove_const<T> {};
///
/// \brief shorthand for `typename remove_const<T>::type`
template<typename T> using remove_const_t = typename remove_const<T>::type;
// specialization for const types
template<typename T> struct remove_const<const T> : type_identity<T> {};
///
@@ -266,30 +263,24 @@ template<typename T> struct remove_const<const T> : type_identity<T> {};
///
/// \details removes references from the provided type such that `T` becomes `volatile T`
/// \tparam T Reference Type
template<typename T> struct add_volatile : type_identity<volatile T> {};
template<typename T> struct add_volatile : detail::_add_volatile<T> {};
///
/// \brief shorthand for `typename add_volatile<T>::type`
template<typename T> using add_volatile_t = typename add_volatile<T>::type;
// specialization for volatile types
template<typename T> struct add_volatile<volatile T> : type_identity<volatile T> {};
///
/// \brief remove the volatile qualifier from the provided type \p T
///
/// \details removes references from the provided type such that `volatile T` becomes `T`
/// \tparam T Reference Type
template<typename T> struct remove_volatile : type_identity<T> {};
template<typename T> struct remove_volatile : detail::_remove_volatile<T> {};
///
/// \brief shorthand for `typename remove_volatile<T>::type`
template<typename T> using remove_volatile_t = typename remove_volatile<T>::type;
// specialization for volatile types
template<typename T> struct remove_volatile<volatile T> : type_identity<T> {};
///
@@ -298,21 +289,12 @@ template<typename T> struct remove_volatile<volatile T> : type_identity<T> {};
/// \details removes references from the provided type such that `T`, `const T`, and `volatile T` become
/// `const volatile T`
/// \tparam T Reference Type
template<typename T> struct add_cv : type_identity<const volatile T> {};
template<typename T> struct add_cv : detail::_add_cv<T> {};
///
/// \brief shorthand for `typename add_cv<T>::type`
template<typename T> using add_cv_t = typename add_cv<T>::type;
// specialization for const types
template<typename T> struct add_cv<const T> : type_identity<const volatile T> {};
// specialization for volatile types
template<typename T> struct add_cv<volatile T> : type_identity<const volatile T> {};
// specialization for const volatile types
template<typename T> struct add_cv<const volatile T> : type_identity<const volatile T> {};
///
@@ -321,16 +303,7 @@ template<typename T> struct add_cv<const volatile T> : type_identity<const volat
/// \details removes const and volatile from the provided type such that `const T`, `volatile T`, and
/// `const volatile T` become `T`
/// \tparam T Reference Type
template<typename T> struct remove_cv : type_identity<T> {};
// specialization for const types
template<typename T> struct remove_cv<const T> : type_identity<T> {};
// specialization for volatile types
template<typename T> struct remove_cv<volatile T> : type_identity<T> {};
// specialization for const volatile types
template<typename T> struct remove_cv<const volatile T> : type_identity<T> {};
template<typename T> struct remove_cv : detail::_remove_cv<T> {};
///
/// \brief shorthand for `typename remove_cv<T>::type`
@@ -343,11 +316,11 @@ template<typename T> using remove_cv_t = typename remove_cv<T>::type;
///
/// \details adds references and const volatile qualifiers to the provided type.
/// \tparam T Reference Type
template<typename T> struct add_cvr : type_identity<add_reference_t<add_cv_t<T>>> {};
template<typename T> struct add_cvref : type_identity<add_reference_t<add_cv_t<T>>> {};
///
/// \brief shorthand for `typename add_cvr<T>::type`
template<typename T> using add_cvr_t = typename add_cvr<T>::type;
template<typename T> using add_cvref_t = typename add_cvref<T>::type;
@@ -356,12 +329,12 @@ template<typename T> using add_cvr_t = typename add_cvr<T>::type;
///
/// \details removes const and volatile from the provided type such that
/// \tparam T Reference Type
template<typename T> struct remove_cvr : type_identity<remove_cv_t<remove_reference_t<T>>> {};
template<typename T> struct remove_cvref : type_identity<remove_cv_t<remove_reference_t<T>>> {};
///
/// \brief shorthand for `typename remove_cvr<T>::type`
template<typename T> using remove_cvr_t = typename remove_cvr<T>::type;
template<typename T> using remove_cvref_t = typename remove_cvref<T>::type;
@@ -370,12 +343,12 @@ template<typename T> using remove_cvr_t = typename remove_cvr<T>::type;
///
/// \details removes const and volatile from the provided type such that
/// \tparam T Reference Type
template<typename T> struct remove_cvrp : type_identity<remove_cv_t<remove_reference_t<strip_pointers_t<T>>>> {};
template<typename T> struct remove_cvrefptr : type_identity<remove_cv_t<remove_reference_t<strip_pointers_t<T>>>> {};
///
/// \brief shorthand for `typename remove_cvrp_t<T>::type`
template<typename T> using remove_cvrp_t = typename remove_cvrp<T>::type;
template<typename T> using remove_cvrefptr_t = typename remove_cvrefptr<T>::type;
}

View File

@@ -71,7 +71,7 @@ namespace fennec
///
/// \brief check if \p T is a fennec::vector type
/// \tparam T type to check
template<typename T> struct is_vector : detail::_is_vector_helper<remove_cvr_t<T>>{};
template<typename T> struct is_vector : detail::_is_vector_helper<remove_cvref_t<T>>{};
///
/// \brief shorthand for ```is_vector<T>::value```
@@ -81,7 +81,7 @@ 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
/// \tparam T type to check
template<typename T> struct component_count : detail::_component_count_helper<remove_cvr_t<T>>{};
template<typename T> struct component_count : detail::_component_count_helper<remove_cvref_t<T>>{};
///
/// \brief shorthand for ```component_count<T>::value```

View File

@@ -20,6 +20,7 @@
#define FENNEC_MEMORY_POINTERS_H
#include <fennec/lang/type_traits.h>
#include <fennec/lang/utility.h>
namespace fennec
{
@@ -176,6 +177,10 @@ public:
return _handle;
}
operator bool() const {
return _handle != nullptr;
}
private:
delete_t _delete;

View File

@@ -94,10 +94,7 @@ enum feature_ : uint32_t {
using featureset_t = bitfield<feature_count>;
using window_id = uint32_t;
using window_pool = object_pool<window*>;
struct config {
};
using window_pool = object_pool<unique_ptr<window>>;
// Public Members ======================================================================================================
@@ -115,11 +112,7 @@ enum feature_ : uint32_t {
return features.test(feature);
}
virtual window* create_window(const window::config& conf) = 0;
window* get_window(size_t id) {
return id == window::nullid ? nullptr : windows[id];
}
virtual window* create_window(const window::config&, window* = nullptr) = 0;
virtual void connect() = 0;
virtual void disconnect() = 0;
@@ -135,7 +128,6 @@ enum feature_ : uint32_t {
protected:
featureset_t features;
window_pool windows;
unique_ptr<gfxcontext> gfx_context;
FENNEC_RTTI_CLASS_ENABLE() {

View File

@@ -19,9 +19,10 @@
#ifndef FENNEC_PLATFORM_INTERFACE_PLATFORM_H
#define FENNEC_PLATFORM_INTERFACE_PLATFORM_H
#include <fennec/platform/interface/display_server.h>
#include <fennec/string/cstring.h>
#include <fennec/platform/window_manager.h>
#include <fennec/rtti/enable.h>
#include <fennec/rtti/singleton.h>
#include <fennec/rtti/detail/_this_t.h>
@@ -79,10 +80,8 @@ public:
virtual void initialize(); // Initialize Drivers and Contexts
virtual void shutdown(); // Close Drivers and Contexts
display_server* get_display_server() { return display.get(); }
protected:
unique_ptr<display_server> display;
unique_ptr<window_manager> wmanager;
FENNEC_RTTI_CLASS_ENABLE() {
}

View File

@@ -39,6 +39,7 @@
#include <fennec/containers/bitfield.h>
#include <fennec/containers/optional.h>
#include <fennec/memory/pointers.h>
namespace fennec
{
@@ -112,20 +113,14 @@ public:
double_t fractional_scaling;
};
window(display_server* server, size_t id, const config& conf)
: server(server), id(id)
, cfg(conf), state(), root(nullptr) {
state.mode = conf.mode;
}
window(display_server* server, const config& conf, window* parent);
virtual ~window() = default;
size_t get_id() const { return id; }
size_t get_parent_id() const { return cfg.parent; }
virtual ~window();
const config& get_config() const { return cfg; }
window* get_parent() const;
window* get_parent() const { return parent; }
window* get_root() const { return root; }
const ivec2& get_size() const { return state.rect.size; }
const ivec2& get_position() const { return state.rect.position; }
@@ -135,7 +130,6 @@ public:
int get_pos_x() const { return state.rect.position.x; }
int get_pos_y() const { return state.rect.position.y; }
bool is_visible() const { return state.flags.test(state_visible); }
bool is_child() const { return state.flags.test(state_child); }
bool is_running() const { return state.flags.test(state_running); }
@@ -174,18 +168,18 @@ public:
protected:
display_server* const server;
const size_t id;
window* const parent;
config cfg;
state state;
window* root;
gfxsurface* gfx_surface;
unique_ptr<gfxsurface> gfx_surface;
};
template<typename DisplayT>
class window_base : public window {
public:
window_base(display_server* display, size_t id, const config& conf)
: window(display, id, conf) {
window_base(display_server* display, const config& conf, window* parent)
: window(display, conf, parent) {
}
using display_t = DisplayT;

View File

@@ -64,7 +64,7 @@ public:
void dispatch() override;
window* create_window(const window::config& conf) override;
window* create_window(const window::config& conf, window* parent) override;
void* get_native_handle() override { return display; }

View File

@@ -50,7 +50,7 @@ namespace fennec
class wayland_window : public window_base<wayland_server> {
public:
wayland_window(display_server* server, uint32_t id, const config& cfg);
wayland_window(display_server* server, const config& cfg, window* parent);
~wayland_window();
void initialize() override;

View File

@@ -0,0 +1,91 @@
// =====================================================================================================================
// fennec, a free and open source game engine
// Copyright © 2025 Medusa Slockbower
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#include <fennec/platform/window_manager.h>
#include <fennec/core/logger.h>
#include <fennec/platform/interface/platform.h>
#include <fennec/platform/interface/display_server.h>
#include <fennec/platform/interface/window.h>
namespace fennec {
window_manager::window_manager(platform* platform)
: _platform(platform) {
}
window_manager::~window_manager() {
shutdown();
}
void window_manager::initialize() {
if (_display) {
return;
}
// Get the list of registered display servers
display_server::entrylist_t display_servers = display_server::get_type_list();
// Find first valid server
while (not display_servers.empty()) {
display_server::entry it = display_servers.front();
display_servers.pop();
unique_ptr<display_server> server = unique_ptr(it.ctor(_platform));
server->connect();
if (server->connected()) {
logger::log(format("Selected {} for the display server.", server->get_type().name()));
_display = move(server);
break;
}
}
assertf(_display, "Failed to select a display server!");
_thread = thread::current();
logger::log(format("Initializing Window Manager on thread: {:#016x}.", _thread));
}
void window_manager::shutdown() {
if (not _display) {
return;
}
assertf(_thread == thread::current(), "Attempted to shutdown Window Manager on a different thread!");
// Cleanup Windows
for (auto& window : _windows) {
window->shutdown();
window.reset();
}
_windows.clear();
// Cleanup Display Server
_display->disconnect();
_display.reset();
}
void window_manager::dispatch() {
assertf(_thread == thread::current(), "Attempted to shutdown Window Manager on a different thread!");
_display->dispatch();
}
} // fennec

View File

@@ -29,20 +29,52 @@
///
#ifndef FENNEC_PLATFORM_WINDOW_MANAGER_H
#define FENNEC_PLATFORM_WINDOW_MANAGER_H
#ifndef FENNEC_PLATFORM_WINDOWMANAGER_H
#define FENNEC_PLATFORM_WINDOWMANAGER_H
#include <fennec/platform/interface/fwd.h>
#include <fennec/memory/pointers.h>
#include <fennec/containers/object_pool.h>
#include <fennec/threading/thread.h>
namespace fennec
{
///
/// \brief Thread-Safe wrapper for `display_server` and `window`
class window_manager {
// Definitions =========================================================================================================
private:
using server_t = unique_ptr<display_server>;
using window_t = unique_ptr<window>;
using window_pool_t = object_pool<window_t>;
// Constructors & Destructor ===========================================================================================
public:
window_manager(platform* platform);
~window_manager();
window_manager(const window_manager&) = delete;
// Thread-Specific Functions ===========================================================================================
void initialize();
void shutdown();
void dispatch();
// Thread-Safe Functions ===============================================================================================
private:
thread::id _thread;
platform* _platform;
server_t _display;
window_pool_t _windows;
};
}
} // fennec
#endif // FENNEC_PLATFORM_WINDOW_MANAGER_H
#endif // FENNEC_PLATFORM_WINDOWMANAGER_H

View File

@@ -34,7 +34,6 @@
namespace fennec
{
class function;
struct vtypelist;
template<typename...> struct typelist;

View File

@@ -78,7 +78,7 @@ private:
template<typename T>
static unique_ptr<type_data> _make_data() {
using raw_t = remove_cvrp_t<T>;
using raw_t = remove_cvrefptr_t<T>;
using supers_t = detect_t<typelist<>, _super_class_list, T>;
auto res = fennec::unique_ptr<type_data>(new type_data{

View File

@@ -43,7 +43,7 @@ namespace fennec
template<typename BaseT, typename...ArgsT>
class type_registry {
public:
using ctor_t = BaseT* (*)(ArgsT&&...);
using ctor_t = BaseT* (*)(ArgsT...);
struct entry {
size_t priority;
@@ -113,8 +113,8 @@ private:
}
template<typename T>
static BaseT* _constructor_helper(ArgsT&&...args) {
return new T(fennec::forward<ArgsT>(args)...);
static BaseT* _constructor_helper(ArgsT...args) {
return new T(args...);
}
};

View File

@@ -0,0 +1,454 @@
// =====================================================================================================================
// 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 atomic.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_THREADING_ATOMIC_H
#define FENNEC_THREADING_ATOMIC_H
#include <fennec/threading/detail/_atomic.h>
#include <fennec/lang/type_traits.h>
namespace fennec
{
using ::memory_order;
using ::memory_order_relaxed;
using ::memory_order_consume;
using ::memory_order_acquire;
using ::memory_order_release;
using ::memory_order_acq_rel;
using ::memory_order_seq_cst;
///
/// \brief Wrapper for atomic variables
/// \tparam T The type of the atomic variable
template<typename T>
struct atomic {
// Assertions ==========================================================================================================
public:
static_assert(is_integral_v<T>, "fennec::atomic not defined for the provided type. Default implementation"
"only supports integral types.");
// Definitions =========================================================================================================
public:
using value_t = T;
// Constructors ========================================================================================================
///
/// \brief Default Constructor
///
/// \details Initializes the held atomic variable with `0`.
constexpr atomic() noexcept
: _value(static_cast<T>(0)) {
}
///
/// \brief Value Constructor
///
/// \details Initializes the held atomic variable with `value`.
/// \param value The value to initialize the atomic variable with.
constexpr atomic(const T value) noexcept
: _value(value) {
}
atomic(const atomic&) = delete;
// Assignment ==========================================================================================================
atomic& operator=(const atomic&) = delete;
atomic& operator=(const atomic&) volatile = delete;
///
/// \details Atomically assigns `x` to the atomic variable.
/// \param x The value to assign
/// \returns `x`
T operator=(const T x) noexcept {
this->store(x);
return x;
}
///
/// \brief Stores a value into an atomic object
///
/// \details Atomically assigns `x` to the atomic variable.
/// \param x The value to assign
/// \returns `x`
T operator=(const T x) volatile noexcept {
this->store(x);
return x;
}
// Modifiers ===========================================================================================================
///
/// \details Atomically replaces the current value with `x`. Memory is affected according to the value of `order`.
/// \param x The value to store into the atomic variable
/// \param order Memory order constraints to enforce
void store(const T x, memory_order order = memory_order_seq_cst) noexcept {
::atomic_store_explicit(&_value, x, order);
}
///
/// \brief Atomically replaces the value of the atomic object with a non-atomic argument
///
/// \details Atomically replaces the current value with `x`. Memory is affected according to the value of `order`.
/// \param x The value to store into the atomic variable
/// \param order Memory order constraints to enforce
void store(const T x, memory_order order = memory_order_seq_cst) volatile noexcept {
::atomic_store_explicit(&_value, x, order);
}
///
/// \details Atomically loads and returns the current value of the atomic variable.
/// Memory is affected according to the value of `order`.
/// \param order Memory order constraints to enforce
/// \returns The current value of the atomic variable.
T load(memory_order order = memory_order_seq_cst) const noexcept {
return ::atomic_load_explicit(&_value, order);
}
///
/// \brief Atomically obtains the value of the atomic object
///
/// \details Atomically loads and returns the current value of the atomic variable.
/// Memory is affected according to the value of `order`.
/// \param order Memory order constraints to enforce
/// \returns The current value of the atomic variable.
T load(memory_order order = memory_order_seq_cst) const volatile noexcept {
return ::atomic_load_explicit(&_value, order);
}
///
/// \details Atomically loads and returns the current value of the atomic variable. Equivalent to `load()`.
operator T() const noexcept {
return load();
}
///
/// \brief Loads a value from an atomic object
///
/// \details Atomically loads and returns the current value of the atomic variable. Equivalent to `load()`.
operator T() const volatile noexcept {
return load();
}
///
/// \details Atomically replaces the underlying value with `x` (a read-modify-write operation).
/// Memory is affected according to the value of `order`.
/// \param x Value to assign
/// \param order Memory order constraints to enforce
/// \return The value of the atomic variable before the call.
T exchange(const T x, memory_order order = memory_order_seq_cst) noexcept {
return ::atomic_exchange_explicit(&_value, x, order);
}
///
/// \brief Atomically replaces the value of the atomic object and obtains the value held previously
///
/// \details Atomically replaces the underlying value with `x` (a read-modify-write operation).
/// Memory is affected according to the value of `order`.
/// \param x Value to assign
/// \param order Memory order constraints to enforce
/// \return The value of the atomic variable before the call.
T exchange(const T x, memory_order order = memory_order_seq_cst) volatile noexcept {
return ::atomic_exchange_explicit(&_value, x, order);
}
///
/// \details Atomically compares the value of `*this` with that of `exp`.
/// If they are equal, replaces the former with `x` (performs read-modify-write operation).
/// Otherwise, loads the actual value stored in *this into `exp` (performs load operation).
/// \param exp Reference to the value expected to be found in the atomic object.
/// \param x The value to store in the atomic object if it is as expected.
/// \param succ The memory synchronization ordering for the read-modify-write operation if the comparison succeeds.
/// \param fail The memory synchronization ordering for the load operation if the comparison fails.
/// \param order The memory synchronization ordering for both operations.
/// \returns `true` if the underlying atomic value was successfully changed, `false` otherwise.
bool compare_exchange_weak(T& exp, T x, memory_order succ, memory_order fail) noexcept {
return ::atomic_compare_exchange_weak_explicit(&_value, &exp, x, succ, fail);
}
///
/// \details Atomically compares the value of `*this` with that of `exp`.
/// If they are equal, replaces the former with `x` (performs read-modify-write operation).
/// Otherwise, loads the actual value stored in *this into `exp` (performs load operation).
/// \param exp Reference to the value expected to be found in the atomic object.
/// \param x The value to store in the atomic object if it is as expected.
/// \param succ The memory synchronization ordering for the read-modify-write operation if the comparison succeeds.
/// \param fail The memory synchronization ordering for the load operation if the comparison fails.
/// \param order The memory synchronization ordering for both operations.
/// \returns `true` if the underlying atomic value was successfully changed, `false` otherwise.
bool compare_exchange_weak(T& exp, T x, memory_order succ, memory_order fail) volatile noexcept {
return ::atomic_compare_exchange_weak_explicit(&_value, &exp, x, succ, fail);
}
///
/// \details Atomically compares the value of `*this` with that of `exp`.
/// If they are equal, replaces the former with `x` (performs read-modify-write operation).
/// Otherwise, loads the actual value stored in *this into `exp` (performs load operation).
/// \param exp Reference to the value expected to be found in the atomic object.
/// \param x The value to store in the atomic object if it is as expected.
/// \param succ The memory synchronization ordering for the read-modify-write operation if the comparison succeeds.
/// \param fail The memory synchronization ordering for the load operation if the comparison fails.
/// \param order The memory synchronization ordering for both operations.
/// \returns `true` if the underlying atomic value was successfully changed, `false` otherwise.
bool compare_exchange_weak(T& exp, T x, memory_order order = memory_order_seq_cst) noexcept {
return ::atomic_compare_exchange_weak_explicit(&_value, &exp, x, order, order);
}
///
/// \brief Atomically compares the value of the atomic object with non-atomic argument and performs atomic exchange if equal or atomic load if not
///
/// \details Atomically compares the value of `*this` with that of `exp`.
/// If they are equal, replaces the former with `x` (performs read-modify-write operation).
/// Otherwise, loads the actual value stored in *this into `exp` (performs load operation).
/// \param exp Reference to the value expected to be found in the atomic object.
/// \param x The value to store in the atomic object if it is as expected.
/// \param succ The memory synchronization ordering for the read-modify-write operation if the comparison succeeds.
/// \param fail The memory synchronization ordering for the load operation if the comparison fails.
/// \param order The memory synchronization ordering for both operations.
/// \returns `true` if the underlying atomic value was successfully changed, `false` otherwise.
bool compare_exchange_weak(T& exp, T x, memory_order order = memory_order_seq_cst) volatile noexcept {
return ::atomic_compare_exchange_weak_explicit(&_value, &exp, x, order, order);
}
///
/// \details Atomically compares the value of `*this` with that of `exp`.
/// If they are equal, replaces the former with `x` (performs read-modify-write operation).
/// Otherwise, loads the actual value stored in *this into `exp` (performs load operation).
/// \param exp Reference to the value expected to be found in the atomic object.
/// \param x The value to store in the atomic object if it is as expected.
/// \param succ The memory synchronization ordering for the read-modify-write operation if the comparison succeeds.
/// \param fail The memory synchronization ordering for the load operation if the comparison fails.
/// \param order The memory synchronization ordering for both operations.
/// \returns `true` if the underlying atomic value was successfully changed, `false` otherwise.
bool compare_exchange_strong(T& exp, T x, memory_order succ, memory_order fail) noexcept {
return ::atomic_compare_exchange_strong_explicit(&_value, &exp, x, succ, fail);
}
///
/// \details Atomically compares the value of `*this` with that of `exp`.
/// If they are equal, replaces the former with `x` (performs read-modify-write operation).
/// Otherwise, loads the actual value stored in *this into `exp` (performs load operation).
/// \param exp Reference to the value expected to be found in the atomic object.
/// \param x The value to store in the atomic object if it is as expected.
/// \param succ The memory synchronization ordering for the read-modify-write operation if the comparison succeeds.
/// \param fail The memory synchronization ordering for the load operation if the comparison fails.
/// \param order The memory synchronization ordering for both operations.
/// \returns `true` if the underlying atomic value was successfully changed, `false` otherwise.
bool compare_exchange_strong(T& exp, T x, memory_order succ, memory_order fail) volatile noexcept {
return ::atomic_compare_exchange_strong_explicit(&_value, &exp, x, succ, fail);
}
///
/// \details Atomically compares the value of `*this` with that of `exp`.
/// If they are equal, replaces the former with `x` (performs read-modify-write operation).
/// Otherwise, loads the actual value stored in *this into `exp` (performs load operation).
/// \param exp Reference to the value expected to be found in the atomic object.
/// \param x The value to store in the atomic object if it is as expected.
/// \param succ The memory synchronization ordering for the read-modify-write operation if the comparison succeeds.
/// \param fail The memory synchronization ordering for the load operation if the comparison fails.
/// \param order The memory synchronization ordering for both operations.
/// \returns `true` if the underlying atomic value was successfully changed, `false` otherwise.
bool compare_exchange_strong(T& exp, T x, memory_order order = memory_order_seq_cst) noexcept {
return ::atomic_compare_exchange_strong_explicit(&_value, &exp, x, order, order);
}
///
/// \brief Atomically compares the value of the atomic object with non-atomic argument and performs atomic exchange if equal or atomic load if not
///
/// \details Atomically compares the value of `*this` with that of `exp`.
/// If they are equal, replaces the former with `x` (performs read-modify-write operation).
/// Otherwise, loads the actual value stored in *this into `exp` (performs load operation).
/// \param exp Reference to the value expected to be found in the atomic object.
/// \param x The value to store in the atomic object if it is as expected.
/// \param succ The memory synchronization ordering for the read-modify-write operation if the comparison succeeds.
/// \param fail The memory synchronization ordering for the load operation if the comparison fails.
/// \param order The memory synchronization ordering for both operations.
/// \returns `true` if the underlying atomic value was successfully changed, `false` otherwise.
bool compare_exchange_strong(T& exp, T x, memory_order order = memory_order_seq_cst) volatile noexcept {
return ::atomic_compare_exchange_strong_explicit(&_value, &exp, x, order, order);
}
// Operations ==========================================================================================================
T fetch_add(const T x, memory_order order = memory_order_seq_cst) noexcept {
return ::atomic_fetch_add_explicit(&_value, x, order);
}
T fetch_add(const T x, memory_order order = memory_order_seq_cst) volatile noexcept {
return ::atomic_fetch_add_explicit(&_value, x, order);
}
T operator+=(const T x) noexcept {
return this->fetch_add(x) + x;
}
T operator+=(const T x) volatile noexcept {
return this->fetch_add(x) + x;
}
T operator++() noexcept {
return this->fetch_add(1) + 1;
}
T operator++() volatile noexcept {
return this->fetch_add(1) + 1;
}
T operator++(int) noexcept {
return this->fetch_add(1);
}
T operator++(int) volatile noexcept {
return this->fetch_add(1);
}
T fetch_sub(const T x, memory_order order = memory_order_seq_cst) noexcept {
return ::atomic_fetch_sub_explicit(&_value, x, order);
}
T fetch_sub(const T x, memory_order order = memory_order_seq_cst) volatile noexcept {
return ::atomic_fetch_sub_explicit(&_value, x, order);
}
T operator-=(const T x) noexcept {
return this->fetch_sub(x) - x;
}
T operator-=(const T x) volatile noexcept {
return this->fetch_sub(x) - x;
}
T operator--() noexcept {
return this->fetch_sub(1) - 1;
}
T operator--() volatile noexcept {
return this->fetch_sub(1) - 1;
}
T operator--(int) noexcept {
return this->fetch_sub(1);
}
T operator--(int) volatile noexcept {
return this->fetch_sub(1);
}
// Bit Operations ======================================================================================================
T fetch_and(const T x, memory_order order = memory_order_seq_cst) noexcept {
return ::atomic_fetch_and_explicit(&_value, x, order);
}
T fetch_and(const T x, memory_order order = memory_order_seq_cst) volatile noexcept {
return ::atomic_fetch_and_explicit(&_value, x, order);
}
T operator&=(const T x) noexcept {
return this->fetch_and(x) & x;
}
T operator&=(const T x) volatile noexcept {
return this->fetch_and(x) & x;
}
T fetch_or(const T x, memory_order order = memory_order_seq_cst) noexcept {
return ::atomic_fetch_or_explicit(&_value, x, order);
}
T fetch_or(const T x, memory_order order = memory_order_seq_cst) volatile noexcept {
return ::atomic_fetch_or_explicit(&_value, x, order);
}
T operator|=(const T x) noexcept {
return this->fetch_or(x) & x;
}
T operator|=(const T x) volatile noexcept {
return this->fetch_or(x) & x;
}
T fetch_xor(const T x, memory_order order = memory_order_seq_cst) noexcept {
return ::atomic_fetch_xor_explicit(&_value, x, order);
}
T fetch_xor(const T x, memory_order order = memory_order_seq_cst) volatile noexcept {
return ::atomic_fetch_xor_explicit(&_value, x, order);
}
T operator^=(const T x) noexcept {
return this->fetch_xor(x) & x;
}
T operator^=(const T x) volatile noexcept {
return this->fetch_xor(x) & x;
}
private:
_Atomic T _value;
};
}
#endif // FENNEC_THREADING_ATOMIC_H

View File

@@ -0,0 +1,222 @@
// =====================================================================================================================
// fennec, a free and open source game engine
// Copyright © 2025 Medusa Slockbower
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#ifndef FENNEC_LANG_DETAIL_ATOMIC_H
#define FENNEC_LANG_DETAIL_ATOMIC_H
// Define _Atomic as volatile
#ifdef _Atomic
#undef _Atomic
#endif
#define _Atomic volatile
#if FENNEC_COMPILER_GCC
// memory_order ========================================================================================================
enum memory_order {
memory_order_relaxed = __ATOMIC_RELAXED,
memory_order_consume = __ATOMIC_CONSUME,
memory_order_acquire = __ATOMIC_ACQUIRE,
memory_order_release = __ATOMIC_RELEASE,
memory_order_acq_rel = __ATOMIC_ACQ_REL,
memory_order_seq_cst = __ATOMIC_SEQ_CST,
};
// atomic_init =========================================================================================================
template<typename T>
constexpr void atomic_init(_Atomic T* x, const T val) {
*x = val;
}
// atomic_flag =========================================================================================================
struct atomic_flag;
// atomic_flag_test_and_set ============================================================================================
constexpr bool atomic_flag_test_and_set(_Atomic atomic_flag* x) {
return ::__atomic_test_and_set(x, memory_order_seq_cst);
}
constexpr bool atomic_flag_test_and_set_explicit(_Atomic atomic_flag* x, memory_order memorder) {
return ::__atomic_test_and_set(x, memorder);
}
// atomic_flag_clear ===================================================================================================
constexpr void atomic_flag_clear(_Atomic atomic_flag* x) {
return ::__atomic_clear(x, memory_order_seq_cst);
}
constexpr void atomic_flag_clear_explicit(_Atomic atomic_flag* x, memory_order memorder) {
return ::__atomic_clear(x, memorder);
}
// atomic_load =========================================================================================================
template<typename T>
constexpr T atomic_load(_Atomic T* x) {
return ::__atomic_load_n(x, memory_order_seq_cst);
}
template<typename T>
constexpr T atomic_load_explicit(_Atomic T* x, memory_order memorder) {
return ::__atomic_load_n(x, memorder);
}
// atomic_store ========================================================================================================
template<typename T>
constexpr bool atomic_store(_Atomic T* x, const T val) {
return ::__atomic_store_n(x, val, memory_order_seq_cst);
}
template<typename T>
constexpr bool atomic_store_explicit(_Atomic T* x, const T val, memory_order memorder) {
return ::__atomic_store_n(x, val, memorder);
}
// atomic_exchange =====================================================================================================
template<typename T>
constexpr bool atomic_exchange(_Atomic T* x, const T val) {
return ::__atomic_exchange_n(x, val, memory_order_seq_cst);
}
template<typename T>
constexpr bool atomic_exchange_explicit(_Atomic T* x, const T val, memory_order memorder) {
return ::__atomic_exchange_n(x, val, memorder);
}
// atomic_compare_exchange_weak ========================================================================================
template<typename T>
constexpr bool atomic_compare_exchange_weak(_Atomic T* x, T* exp, const T des) {
return ::__atomic_compare_exchange_n(x, exp, des, true, memory_order_seq_cst, memory_order_seq_cst);
}
template<typename T>
constexpr bool atomic_compare_exchange_weak_explicit(_Atomic T* x, T* exp, const T des, memory_order succ, memory_order fail) {
return ::__atomic_compare_exchange_n(x, exp, des, true, succ, fail);
}
// atomic_compare_exchange_strong ======================================================================================
template<typename T>
constexpr bool atomic_compare_exchange_strong(_Atomic T* x, T* exp, const T des) {
return ::__atomic_compare_exchange_n(x, exp, des, false, memory_order_seq_cst, memory_order_seq_cst);
}
template<typename T>
constexpr bool atomic_compare_exchange_strong_explicit(_Atomic T* x, T* exp, const T des, memory_order succ, memory_order fail) {
return ::__atomic_compare_exchange_n(x, exp, des, false, succ, fail);
}
// atomic_fetch_add ====================================================================================================
template<typename T>
constexpr T atomic_fetch_add(_Atomic T* x, const T val) {
return ::__atomic_fetch_add(x, val, memory_order_seq_cst);
}
template<typename T>
constexpr T atomic_fetch_add_explicit(_Atomic T* x, const T val, memory_order memorder) {
return ::__atomic_fetch_add(x, val, memorder);
}
// atomic_fetch_sub ====================================================================================================
template<typename T>
constexpr T atomic_fetch_sub(_Atomic T* x, const T val) {
return ::__atomic_fetch_sub(x, val, memory_order_seq_cst);
}
template<typename T>
constexpr T atomic_fetch_sub_explicit(_Atomic T* x, const T val, memory_order memorder) {
return ::__atomic_fetch_sub(x, val, memorder);
}
// atomic_fetch_or ====================================================================================================
template<typename T>
constexpr T atomic_fetch_or(_Atomic T* x, const T val) {
return ::__atomic_fetch_or(x, val, memory_order_seq_cst);
}
template<typename T>
constexpr T atomic_fetch_or_explicit(_Atomic T* x, const T val, memory_order memorder) {
return ::__atomic_fetch_or(x, val, memorder);
}
// atomic_fetch_xor ====================================================================================================
template<typename T>
constexpr T atomic_fetch_xor(_Atomic T* x, const T val) {
return ::__atomic_fetch_xor(x, val, memory_order_seq_cst);
}
template<typename T>
constexpr T atomic_fetch_xor_explicit(_Atomic T* x, const T val, memory_order memorder) {
return ::__atomic_fetch_xor(x, val, memorder);
}
// atomic_fetch_and ====================================================================================================
template<typename T>
constexpr T atomic_fetch_and(_Atomic T* x, const T val) {
return ::__atomic_fetch_and(x, val, memory_order_seq_cst);
}
template<typename T>
constexpr T atomic_fetch_and_explicit(_Atomic T* x, const T val, memory_order memorder) {
return ::__atomic_fetch_and(x, val, memorder);
}
#endif
#endif // FENNEC_LANG_DETAIL_ATOMIC_H

View File

@@ -0,0 +1,59 @@
// =====================================================================================================================
// fennec, a free and open source game engine
// Copyright © 2025 Medusa Slockbower
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
///
/// \file _thread.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_THREADING_DETAIL_THREAD_H
#define FENNEC_THREADING_DETAIL_THREAD_H
#include <fennec/containers/tuple.h>
#include <fennec/lang/function.h>
#include <fennec/memory/pointers.h>
namespace fennec::detail
{
template<typename FuncT, typename...ArgsT> using thread_proxy_t = tuple<FuncT, ArgsT...>;
template<typename FuncT, typename...ArgsT, size_t...I>
void _execute_thread(thread_proxy_t<function<FuncT>, ArgsT...>& data, index_metasequence<I...>) {
auto func = data.template get<0>();
func(fennec::move(data.template get<I + 1>()) ...);
}
template<typename DataT>
void* _run_thread(void* data) {
unique_ptr<DataT> ptr(data);
detail::_execute_thread(*ptr, make_index_metasequence_t<DataT::size - 1>{});
return nullptr;
}
}
#endif // FENNEC_THREADING_DETAIL_THREAD_H

View File

@@ -0,0 +1,171 @@
// =====================================================================================================================
// 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 thread.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_THREADING_THREAD_H
#define FENNEC_THREADING_THREAD_H
#include <pthread.h>
#include <fennec/format/formatter.h>
#include <fennec/lang/type_traits.h>
#include <fennec/lang/type_transforms.h>
#include <fennec/memory/bytes.h>
#include <fennec/threading/detail/_thread.h>
namespace fennec
{
class thread {
private:
static constexpr pthread_t nullthread = 0;
public:
using native_handle_type = pthread_t;
class id {
public:
constexpr id() noexcept : _id(0) {}
constexpr friend bool operator==(id x, id y) noexcept {
if (x._id == 0) {
return y._id == 0;
}
if (y._id == 0) {
return false;
}
return pthread_equal(x._id, y._id) != 0;
}
constexpr friend bool operator!=(id x, id y) noexcept { return !(x == y); }
private:
friend class thread;
friend struct hash<id>;
friend struct formatter<id>;
constexpr id(pthread_t id) : _id(id) {}
pthread_t _id;
};
thread() noexcept
: _handle(nullthread) {
}
thread(thread&& th)
: _handle(th._handle) {
th._handle = nullthread;
}
thread(const thread&) = delete;
template<typename FuncT, typename...ArgsT>
requires(not is_same_v<thread, remove_cvref_t<FuncT>>)
thread(FuncT&& func, ArgsT&&...args)
: _handle(nullthread) {
using proxy_t = detail::thread_proxy_t<function<FuncT>, ArgsT...>;
unique_ptr<proxy_t> proxy = fennec::make_unique<proxy_t>(fennec::forward<FuncT>(func), fennec::forward<ArgsT>(args)...);
int_t res = ::pthread_create(&_handle, nullptr, &detail::_run_thread<proxy_t>(), proxy.get());
assertf(res == 0, "Thread creation failed!");
proxy.release();
}
thread& operator=(thread&& th) noexcept {
assertf(_handle == nullthread, "Attempted to overwrite running thread!");
_handle = th._handle;
th._handle = nullthread;
return *this;
}
~thread() {
assertf(_handle == 0, "Attempted to destruct a running thread!");
}
bool joinable() const noexcept {
return _handle != nullthread and pthread_self() != _handle;
}
void join() {
if (not joinable()) {
return;
}
int_t res = pthread_join(_handle, nullptr);
assertf(res == 0, "Failed to join thread!");
_handle = nullthread;
}
void detatch() {
if (not joinable()) {
return;
}
int_t res = pthread_detach(_handle);
assertf(res == 0, "Failed to detatch thread!");
_handle = nullthread;
}
void swap(thread& other) {
fennec::swap(_handle, other._handle);
}
static id current() {
return pthread_self();
}
id get_id() const {
return _handle;
}
private:
pthread_t _handle;
};
template <>
struct hash<thread::id> {
size_t operator()(thread::id v) const noexcept {
return hash<thread::native_handle_type>()(v._id);
}
};
template<>
struct formatter<thread::id> {
string operator()(const format_arg& fmt, thread::id v) const noexcept {
return formatter<thread::native_handle_type>()(fmt, v._id);
}
};
}
#endif // FENNEC_THREADING_THREAD_H

View File

@@ -1047,6 +1047,7 @@ void file::println(const cstring& str) {
void file::println(const string& str) {
write(str.data(), str.length());
putc('\n');
}
bool file::putc(char c) {

View File

@@ -29,25 +29,22 @@ platform::platform() {
}
void platform::initialize() {
if (wmanager) {
return;
}
logger::log(format("Initializing platform {}", get_type().name()));
display_server::entrylist_t display_servers = display_server::get_type_list();
while (not display_servers.empty()) {
display_server::entry it = display_servers.front();
display_servers.pop();
unique_ptr<display_server> server = unique_ptr(it.ctor(this));
server->connect();
if (server->connected()) {
logger::log(format("Selected {} for the display server.", server->get_type().name()));
display = move(server);
break;
}
}
// Setup Window Manager
wmanager = make_unique<window_manager>(this);
wmanager->initialize();
}
void platform::shutdown() {
display.reset();
// Cleanup Window Manager
wmanager->shutdown();
wmanager.reset();
}
}

View File

@@ -29,14 +29,20 @@
///
#include <fennec/platform/interface/window.h>
#include <fennec/platform/interface/display_server.h>
#include <fennec/renderers/interface/gfxsurface.h>
#include <fennec/platform/interface/display_server.h>
namespace fennec
{
window* window::get_parent() const {
return server->get_window(cfg.parent);
window::window(display_server* server, const config& conf, window* parent)
: server(server), parent(parent)
, cfg(conf), state(), root(nullptr) {
state.mode = conf.mode;
}
window::~window() {
}
void window::begin_frame() {

View File

@@ -177,9 +177,8 @@ void wayland_server::dispatch() {
}
}
window* wayland_server::create_window(const window::config& conf) {
size_t id = windows.insert(new wayland_window(this, windows.next_id(), conf));
return windows[id];
window* wayland_server::create_window(const window::config& conf, window* parent) {
return new wayland_window(this, conf, parent);
}
void wayland_server::_wl_registry_listen_global(void* data, wl_registry* reg, uint32_t id, const char* name, uint32_t version) {

View File

@@ -20,6 +20,7 @@
#include <fennec/math/relational.h>
#include <fennec/platform/interface/display_server.h>
#include <fennec/renderers/interface/gfxsurface.h>
#include <fennec/renderers/interface/gfxcontext.h>
#include <fennec/platform/linux/wayland/server.h>
@@ -27,7 +28,6 @@
#include <fennec/platform/linux/wayland/lib/wayland.h>
#include <fennec/platform/linux/wayland/lib/headers/xdg-shell-client-protocols.h>
#include <fennec/platform/linux/wayland/libdecor/libdecor.h>
#include <fennec/renderers/interface/gfxsurface.h>
#if FENNEC_HAS_LIBDECOR
#include <fennec/platform/linux/wayland/libdecor/libdecor.h>
@@ -35,11 +35,10 @@
using namespace fennec;
wayland_window::wayland_window(display_server* server, uint32_t id, const config& cfg)
: window_base(server, id, cfg)
wayland_window::wayland_window(display_server* server, const config& cfg, window* parent)
: window_base(server, cfg, parent)
, surface(nullptr)
, xdgsurface(nullptr) {
}
wayland_window::~wayland_window() {
@@ -79,7 +78,7 @@ void wayland_window::initialize() {
}
wayland_window* root = this;
root = parent;
while (root != nullptr and root->is_popup()) {
root = static_cast<wayland_window*>(root->get_parent());
}
@@ -110,7 +109,7 @@ void wayland_window::initialize() {
.reserved9 = nullptr,
};
gfx_surface = wl_server->get_gfx_context()->create_surface(this);
gfx_surface = unique_ptr(wl_server->get_gfx_context()->create_surface(this));
if (wl_server->has_libdecor) {
@@ -151,11 +150,6 @@ void wayland_window::shutdown() {
wayland_server* wl_server = static_cast<wayland_server*>(server);
if (frame_callback) {
wl_callback_destroy(frame_callback);
frame_callback = nullptr;
}
#if FENNEC_HAS_LIBDECOR
if (libdecorframe) {
libdecor_frame_unref(libdecorframe);
@@ -164,6 +158,15 @@ void wayland_window::shutdown() {
}
#endif
if (gfx_surface) {
gfx_surface.reset();
}
if (frame_callback) {
wl_callback_destroy(frame_callback);
frame_callback = nullptr;
}
if (xdgtoplevel) {
xdg_toplevel_destroy(xdgtoplevel);
xdgtoplevel = nullptr;

View File

@@ -7,6 +7,8 @@ set(CMAKE_C_STANDARD 23)
add_executable(fennec-test
main.cpp
tests/lang/test_metaprogramming.h
tests/lang/test_function.h
tests/test_threading.h
)
target_compile_definitions(fennec-test PUBLIC FENNEC_TEST_CWD="${CMAKE_SOURCE_DIR}/bin/${FENNEC_BUILD_NAME}"

View File

@@ -27,6 +27,7 @@
#include "tests/test_filesystem.h"
#include "tests/test_platform.h"
#include "tests/test_rtti.h"
#include "tests/test_threading.h"
int main(int, char **)
{
@@ -66,9 +67,9 @@ int main(int, char **)
fennec::test::fennec_test_filesystem();
fennec_test_spacer(3);
fennec_test_header("platform library");
fennec_test_header("threading");
fennec_test_spacer(2);
fennec::test::fennec_test_platform();
fennec::test::fennec_test_threading();
fennec_test_spacer(3);
fennec_test_header("rtti library");
@@ -76,5 +77,10 @@ int main(int, char **)
fennec::test::fennec_test_rtti();
fennec_test_spacer(3);
fennec_test_header("platform library");
fennec_test_spacer(2);
fennec::test::fennec_test_platform();
fennec_test_spacer(3);
return 0;
}

View File

@@ -0,0 +1,64 @@
// =====================================================================================================================
// 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 test_function.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_TEST_LANG_FUNCTION_H
#define FENNEC_TEST_LANG_FUNCTION_H
#include "../../test.h"
#include <fennec/lang/function.h>
namespace fennec::test
{
inline bool fennec_test_lang_function_test() {
return true;
}
inline void fennec_test_lang_function() {
function<bool()> test;
fennec_test_run((bool)(test = fennec_test_lang_function_test), true);
fennec_test_run(test(), true);
fennec_test_spacer(1);
fennec_test_run((bool)(test = []() { return true; }), true);
fennec_test_run(test(), true);
fennec_test_spacer(1);
fennec_test_run((bool)(test = nullptr), false);
}
}
#endif // FENNEC_TEST_LANG_FUNCTION_H

View File

@@ -21,6 +21,7 @@
#include "lang/test_bits.h"
#include "lang/test_conditional_types.h"
#include "lang/test_function.h"
#include "lang/test_hashing.h"
#include "lang/test_metaprogramming.h"
@@ -41,6 +42,11 @@ namespace fennec::test
fennec_test_subheader("metaprogramming tests");
fennec_test_spacer(2);
fennec_test_lang_metaprogramming();
fennec_test_spacer(3);
fennec_test_subheader("function tests");
fennec_test_spacer(2);
fennec_test_lang_function();
// TODO
}

View File

@@ -32,6 +32,7 @@ inline void fennec_test_platform() {
platform* platform = platform::instance();
platform->initialize();
/*
display_server* display = platform->get_display_server();
window* window = display->create_window(window::config {
@@ -59,8 +60,7 @@ inline void fennec_test_platform() {
}
window->shutdown();
delete window;
*/
platform::instance()->shutdown();

View File

@@ -0,0 +1,48 @@
// =====================================================================================================================
// fennec, a free and open source game engine
// Copyright © 2025 Medusa Slockbower
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
///
/// \file test_threading.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_TEST_THREADING_H
#define FENNEC_TEST_THREADING_H
#include <fennec/threading/atomic.h>
namespace fennec::test
{
inline void fennec_test_threading() {
atomic<bool> test;
}
}
#endif // FENNEC_TEST_THREADING_H