- 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

@@ -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); }
@@ -173,19 +167,19 @@ public:
virtual void* get_native_handle() = 0;
protected:
display_server* const server;
const size_t id;
config cfg;
state state;
window* root;
gfxsurface* gfx_surface;
display_server* const server;
window* const parent;
config cfg;
state state;
window* root;
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