From aee4e340dd97e4822335bd825e08ba33ff7a91a6 Mon Sep 17 00:00:00 2001 From: Medusa Slockbower Date: Wed, 17 Dec 2025 01:11:28 -0500 Subject: [PATCH] - Started setting up a thread safe window manager - Created thread & atomic structures --- CMakeLists.txt | 73 +- cmake/gcc.cmake | 4 +- cmake/opengl.cmake | 1 + include/fennec/containers/list.h | 4 +- include/fennec/containers/object_pool.h | 132 +++ include/fennec/core/logger.h | 4 +- include/fennec/lang/detail/_function.h | 45 ++ include/fennec/lang/detail/_type_traits.h | 6 + include/fennec/lang/detail/_type_transforms.h | 30 + include/fennec/lang/function.h | 87 ++ include/fennec/lang/hashing.h | 1 + include/fennec/lang/intrinsics.h | 77 +- include/fennec/lang/type_traits.h | 760 ++++++++++++------ include/fennec/lang/type_transforms.h | 67 +- include/fennec/math/vector_traits.h | 4 +- include/fennec/memory/pointers.h | 5 + .../platform/interface/display_server.h | 12 +- include/fennec/platform/interface/platform.h | 7 +- include/fennec/platform/interface/window.h | 32 +- .../fennec/platform/linux/wayland/server.h | 2 +- .../fennec/platform/linux/wayland/window.h | 2 +- include/fennec/platform/window_manager.cpp | 91 +++ include/fennec/platform/window_manager.h | 44 +- include/fennec/rtti/forward.h | 1 - include/fennec/rtti/type_data.h | 2 +- include/fennec/rtti/type_registry.h | 6 +- include/fennec/threading/atomic.h | 454 +++++++++++ include/fennec/threading/detail/_atomic.h | 222 +++++ include/fennec/threading/detail/_thread.h | 59 ++ include/fennec/threading/thread.h | 171 ++++ source/filesystem/file.cpp | 1 + source/platform/interface/platform.cpp | 25 +- source/platform/interface/window.cpp | 12 +- source/platform/linux/wayland/server.cpp | 5 +- source/platform/linux/wayland/window.cpp | 25 +- test/CMakeLists.txt | 2 + test/main.cpp | 10 +- test/tests/lang/test_function.h | 64 ++ test/tests/test_lang.h | 6 + test/tests/test_platform.h | 4 +- test/tests/test_threading.h | 48 ++ 41 files changed, 2179 insertions(+), 428 deletions(-) create mode 100644 include/fennec/lang/detail/_function.h create mode 100644 include/fennec/lang/function.h create mode 100644 include/fennec/platform/window_manager.cpp create mode 100644 include/fennec/threading/atomic.h create mode 100644 include/fennec/threading/detail/_atomic.h create mode 100644 include/fennec/threading/detail/_thread.h create mode 100644 include/fennec/threading/thread.h create mode 100644 test/tests/lang/test_function.h create mode 100644 test/tests/test_threading.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 182ab02..07a2c96 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,13 +16,13 @@ # along with this program. If not, see . # ====================================================================================================================== -cmake_minimum_required(VERSION 3.28) +cmake_minimum_required(VERSION 3.28...3.31) project(fennec) set(FENNEC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) macro(fennec_add_sources) - list(APPEND FENNEC_EXTRA_SOURCES ${ARGN}) + list(APPEND FENNEC_SOURCES ${ARGN}) endmacro() macro(fennec_add_definitions) @@ -37,6 +37,10 @@ macro(fennec_add_shared_libraries) list(APPEND FENNEC_SHARED_LIBRARIES ${ARGN}) endmacro() +macro(fennec_add_compile_options) + list(APPEND FENNEC_PRIVATE_COMPILE_OPTIONS ${ARGN}) +endmacro() + macro(fennec_add_link_options) list(APPEND FENNEC_PRIVATE_LINK_OPTIONS ${ARGN}) endmacro() @@ -76,12 +80,9 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${FENNEC_SOURCE_DIR}/lib/${FENNEC_BUILD_NAME} set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${FENNEC_SOURCE_DIR}/lib/${FENNEC_BUILD_NAME}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${FENNEC_SOURCE_DIR}/bin/${FENNEC_BUILD_NAME}) -# add the test suite as a sub-project -add_subdirectory(test) - -add_library(fennec STATIC - -# CORE ================================================================================================================= +# Core Files +fennec_add_sources( + # CORE ================================================================================================================= include/fennec/core/engine.h source/core/engine.cpp include/fennec/core/event.h source/core/event.cpp include/fennec/core/logger.h source/core/logger.cpp @@ -90,7 +91,7 @@ add_library(fennec STATIC include/fennec/core/system.h -# SCENE ================================================================================================================ + # SCENE ================================================================================================================ include/fennec/scene/scene.h source/scene/scene.cpp include/fennec/scene/component.h include/fennec/scene/scene_node.h @@ -99,7 +100,7 @@ add_library(fennec STATIC -# RENDERERS ============================================================================================================ + # RENDERERS ============================================================================================================ include/fennec/renderers/interface/forward.h include/fennec/renderers/interface/gfxcontext.h @@ -107,7 +108,7 @@ add_library(fennec STATIC include/fennec/renderers/interface/gfxresourcepool.h -# CONTAINERS =========================================================================================================== + # CONTAINERS =========================================================================================================== include/fennec/containers/containers.h include/fennec/containers/array.h @@ -135,7 +136,7 @@ add_library(fennec STATIC include/fennec/containers/detail/_tuple.h -# lang ================================================================================================================= + # lang ================================================================================================================= include/fennec/lang/lang.h include/fennec/lang/metaprogramming.h @@ -172,7 +173,7 @@ add_library(fennec STATIC include/fennec/lang/detail/_type_sequences.h -# RTTI ================================================================================================================= + # RTTI ================================================================================================================= include/fennec/rtti/typeid.h include/fennec/rtti/type_data.h include/fennec/rtti/type.h @@ -189,7 +190,7 @@ add_library(fennec STATIC include/fennec/rtti/detail/_type_name.h -# MEMORY =============================================================================================================== + # MEMORY =============================================================================================================== include/fennec/memory/new.h source/memory/new.cpp include/fennec/memory/allocator.h @@ -201,11 +202,11 @@ add_library(fennec STATIC include/fennec/memory/detail/_ptr_traits.h -# DEBUG ================================================================================================================ + # DEBUG ================================================================================================================ source/debug/assert_impl.cpp -# MATH ================================================================================================================= + # MATH ================================================================================================================= include/fennec/math/math.h include/fennec/math/scalar.h @@ -230,6 +231,7 @@ add_library(fennec STATIC include/fennec/math/ext/constants.h include/fennec/math/ext/primes.h include/fennec/math/ext/quaternion.h + include/fennec/math/ext/rect.h include/fennec/math/ext/transform.h @@ -241,7 +243,7 @@ add_library(fennec STATIC -# string =============================================================================================================== + # string =============================================================================================================== include/fennec/string/locale.h include/fennec/string/cstring.h include/fennec/string/string.h @@ -250,7 +252,7 @@ add_library(fennec STATIC -# format =============================================================================================================== + # format =============================================================================================================== include/fennec/format/format.h include/fennec/format/format_arg.h include/fennec/format/formatter.h @@ -262,46 +264,55 @@ add_library(fennec STATIC -# filesystem =========================================================================================================== + # filesystem =========================================================================================================== include/fennec/filesystem/file.h source/filesystem/file.cpp include/fennec/filesystem/path.h source/filesystem/path.cpp -# interpret ============================================================================================================ + # interpret ============================================================================================================ include/fennec/interpret/tokenizer.h -# PLATFORM ============================================================================================================= + # PLATFORM ============================================================================================================= include/fennec/platform/interface/fwd.h include/fennec/platform/interface/display_server.h include/fennec/platform/interface/platform.h source/platform/interface/platform.cpp include/fennec/platform/interface/window.h source/platform/interface/window.cpp -# GRAPHICS ============================================================================================================= + # GRAPHICS ============================================================================================================= include/fennec/gfx3d/mesh_instance.h +) -# EXTRA SOURCES ======================================================================================================== +# add the test suite as a sub-project +add_subdirectory(test) - ${FENNEC_EXTRA_SOURCES} - include/fennec/math/ext/rect.h - include/fennec/platform/opengl/egl/error.h +add_library(fennec STATIC + ${FENNEC_SOURCES} include/fennec/platform/window_manager.h + include/fennec/platform/window_manager.cpp + include/fennec/platform/window_manager.h + include/fennec/lang/function.h + include/fennec/threading/thread.h + include/fennec/threading/detail/_thread.h + include/fennec/lang/detail/_function.h + include/fennec/threading/atomic.h ) add_dependencies(fennec metaprogramming fennec-dependencies) -target_compile_definitions(fennec PUBLIC - ${FENNEC_COMPILE_DEFINITIONS} -) +target_compile_definitions(fennec PUBLIC ${FENNEC_COMPILE_DEFINITIONS}) +target_compile_options(fennec PRIVATE ${FENNEC_PRIVATE_COMPILE_OPTIONS}) - -target_link_options(fennec PRIVATE ${FENNEC_PRIVATE_LINK_OPTIONS}) # Do not compile base fennec library with c++ stdlib +# Do not compile base fennec library with c++ stdlib # fennec does not use the C++ stdlib because it is bloated, difficult to read, and implementation defined. # This implementation is designed to be as readable as possible, and expose information that would otherwise be obfuscated +target_link_options(fennec PRIVATE ${FENNEC_PRIVATE_LINK_OPTIONS}) + + target_link_libraries(fennec PRIVATE ${FENNEC_LINK_LIBRARIES} diff --git a/cmake/gcc.cmake b/cmake/gcc.cmake index 9ef7621..2129711 100644 --- a/cmake/gcc.cmake +++ b/cmake/gcc.cmake @@ -20,7 +20,9 @@ add_compile_options("-Wall" "-Wextra" "-pedantic" "-Werror" "-fms-extensions") -fennec_add_link_options("-nostdlib" "-fno-exceptions" "-fno-rtti" "-fdiagnostics-all-candidates") +fennec_add_compile_options("-ffile-prefix-map=${FENNEC_SOURCE_DIR}=.") + +fennec_add_link_options("-nostdlib" "-fno-exceptions" "-fno-rtti" "-fdiagnostics-all-candidates" "-pthread") fennec_add_definitions( _GLIBCXX_INCLUDE_NEXT_C_HEADERS=1 diff --git a/cmake/opengl.cmake b/cmake/opengl.cmake index 26cd2b6..10b72fd 100644 --- a/cmake/opengl.cmake +++ b/cmake/opengl.cmake @@ -26,6 +26,7 @@ if(FENNEC_GRAPHICS_WANT_EGL) fennec_add_sources( include/fennec/platform/opengl/egl/fwd.h + include/fennec/platform/opengl/egl/error.h include/fennec/platform/opengl/egl/context.h source/platform/opengl/egl/context.cpp include/fennec/platform/opengl/egl/surface.h source/platform/opengl/egl/surface.cpp ) diff --git a/include/fennec/containers/list.h b/include/fennec/containers/list.h index 884b18f..b929bbe 100644 --- a/include/fennec/containers/list.h +++ b/include/fennec/containers/list.h @@ -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(); } /// @} diff --git a/include/fennec/containers/object_pool.h b/include/fennec/containers/object_pool.h index 981e229..032bfc8 100644 --- a/include/fennec/containers/object_pool.h +++ b/include/fennec/containers/object_pool.h @@ -52,6 +52,9 @@ public: using table_t = dynarray; using freed_t = list; + 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; diff --git a/include/fennec/core/logger.h b/include/fennec/core/logger.h index 53c9f85..44be98d 100644 --- a/include/fennec/core/logger.h +++ b/include/fennec/core/logger.h @@ -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(); diff --git a/include/fennec/lang/detail/_function.h b/include/fennec/lang/detail/_function.h new file mode 100644 index 0000000..5069dc5 --- /dev/null +++ b/include/fennec/lang/detail/_function.h @@ -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 . +// ===================================================================================================================== + +/// +/// \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 + +namespace fennec::detail +{ + + + + +} + +#endif // FENNEC_LANG_DETAIL_FUNCTION_H \ No newline at end of file diff --git a/include/fennec/lang/detail/_type_traits.h b/include/fennec/lang/detail/_type_traits.h index 3140897..a025c17 100644 --- a/include/fennec/lang/detail/_type_traits.h +++ b/include/fennec/lang/detail/_type_traits.h @@ -55,6 +55,12 @@ namespace fennec::detail template<> struct _is_integral : true_type {}; template<> struct _is_integral : true_type {}; + template struct _is_const : false_type {}; + template struct _is_const : true_type {}; + + template struct _is_volatile : false_type {}; + template struct _is_volatile : true_type {}; + // Most unsigned types will underflow `-1` to the types maximum value template struct _is_signed : bool_constant {}; template struct _is_unsigned : bool_constant= TypeT(0)> {}; diff --git a/include/fennec/lang/detail/_type_transforms.h b/include/fennec/lang/detail/_type_transforms.h index bfa4ee1..a9a334f 100644 --- a/include/fennec/lang/detail/_type_transforms.h +++ b/include/fennec/lang/detail/_type_transforms.h @@ -20,9 +20,39 @@ #define FENNEC_LANG_DETAIL_TYPE_TRANSFORMS_H #include +#include namespace fennec::detail { + template struct _add_pointer : type_identity {}; + template struct _remove_pointer : type_identity {}; + template struct _remove_pointer : type_identity {}; + + template struct _add_const : type_identity {}; + template struct _remove_const : type_identity {}; + template struct _remove_const : type_identity {}; + + template struct _add_volatile : type_identity {}; + template struct _remove_volatile : type_identity {}; + template struct _remove_volatile : type_identity {}; + + template struct _add_cv : _add_const::type> {}; + template struct _remove_cv : type_identity {}; + template struct _remove_cv : type_identity {}; + template struct _remove_cv : type_identity {}; + template struct _remove_cv : type_identity {}; + + template + struct _decay : conditional<_is_const{}, _remove_cv, _add_pointer> {}; + + template requires requires { typename TypeT::element_t; } + struct _decay : type_identity {}; + + template + struct _decay : type_identity {}; + + template + struct _decay : type_identity {}; template struct _add_lvalue_reference { diff --git a/include/fennec/lang/function.h b/include/fennec/lang/function.h new file mode 100644 index 0000000..6cf4ffb --- /dev/null +++ b/include/fennec/lang/function.h @@ -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 . +// ===================================================================================================================== + +/// +/// \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 +#include +#include + +#include + +namespace fennec +{ + +template class function; + +template +class function { +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(args)...); + } + +private: + ReturnT (*call)(ArgsT&&...) { nullptr }; +}; + +} + +#endif // FENNEC_LANG_FUNCTION_H \ No newline at end of file diff --git a/include/fennec/lang/hashing.h b/include/fennec/lang/hashing.h index 40a2e62..6a115ae 100644 --- a/include/fennec/lang/hashing.h +++ b/include/fennec/lang/hashing.h @@ -21,6 +21,7 @@ #include #include +#include namespace fennec { diff --git a/include/fennec/lang/intrinsics.h b/include/fennec/lang/intrinsics.h index 4162b1e..b0a20f4 100644 --- a/include/fennec/lang/intrinsics.h +++ b/include/fennec/lang/intrinsics.h @@ -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 diff --git a/include/fennec/lang/type_traits.h b/include/fennec/lang/type_traits.h index d1f8de8..38fe857 100644 --- a/include/fennec/lang/type_traits.h +++ b/include/fennec/lang/type_traits.h @@ -147,18 +147,18 @@ /// Description /// ///
-/// \ref fennec::is_fundamental "is_fundamental::value"
-/// \ref fennec::is_fundamental_v "is_fundamental_v" -/// -/// \copydetails fennec::is_fundamental -/// -///
/// \ref fennec::is_arithmetic "is_arithmetic::value"
/// \ref fennec::is_arithmetic_v "is_arithmetic_v" /// /// \copydetails fennec::is_arithmetic /// ///
+/// \ref fennec::is_fundamental "is_fundamental::value"
+/// \ref fennec::is_fundamental_v "is_fundamental_v" +/// +/// \copydetails fennec::is_fundamental +/// +///
/// \ref fennec::is_scalar "is_scalar::value"
/// \ref fennec::is_scalar_v "is_scalar_v" /// @@ -271,12 +271,6 @@ /// \copydetails fennec::is_aggregate /// ///
-/// \ref fennec::is_implicit_lifetime "is_implicit_lifetime::value"
-/// \ref fennec::is_implicit_lifetime_v "is_implicit_lifetime_v" -/// -/// \copydetails fennec::is_implicit_lifetime -/// -///
/// \ref fennec::is_signed "is_signed::value"
/// \ref fennec::is_signed_v "is_signed_v" /// @@ -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 struct is_void - : detail::_is_void>{}; + : detail::_is_void>{}; /// /// \brief Shorthand for ```is_void::value``` @@ -468,7 +462,7 @@ template constexpr bool_t is_void_v = is_void::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 struct is_null_pointer - : detail::_is_null_pointer>{}; + : detail::_is_null_pointer>{}; /// /// \brief Shorthand for ```is_null_pointer::value``` @@ -477,6 +471,57 @@ template constexpr bool_t is_null_pointer_v = is_null_pointer::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 struct is_bool + : detail::_is_bool>{}; + +/// +/// \brief Shorthand for ```is_bool::value``` +/// \tparam T type to check +template constexpr bool_t is_bool_v = is_bool::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 struct is_integral + : detail::_is_integral> {}; + +/// +/// \brief Shorthand for ```is_integral::value``` +/// \tparam T type to check +template constexpr bool_t is_integral_v = is_integral::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 struct is_floating_point + : detail::_is_floating_point>{}; + +/// +/// \brief Shorthand for ```is_floating_point::value``` +/// \tparam T type to check +template constexpr bool_t is_floating_point_v = is_floating_point {}; + + + // fennec::is_array ==================================================================================================== #ifdef FENNEC_BUILTIN_IS_ARRAY @@ -557,7 +602,7 @@ template constexpr size_t is_class_v = is_class::value; -// fennec::is_function ==================================================================================================== +// fennec::is_function ================================================================================================= /// /// \brief Check if \p T is a class @@ -572,41 +617,363 @@ template constexpr size_t is_function_v = is_function::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 struct is_bool - : detail::_is_bool>{}; +template struct is_pointer + : detail::_is_pointer>{}; /// -/// \brief Shorthand for ```is_bool::value``` +/// \brief Shorthand for ```is_pointer::value``` /// \tparam T type to check -template constexpr bool_t is_bool_v = is_bool::value; +template constexpr bool_t is_pointer_v = is_pointer {}; -// 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 struct is_integral - : detail::_is_integral> {}; +template struct is_lvalue_reference + : detail::_is_lvalue_reference{}; /// -/// \brief Shorthand for ```is_integral::value``` +/// \brief Shorthand for ```is_floating_point::value``` /// \tparam T type to check -template constexpr bool_t is_integral_v = is_integral::value; +template constexpr bool_t is_lvalue_reference_v = is_lvalue_reference {}; + + + +// 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 struct is_rvalue_reference + : detail::_is_rvalue_reference{}; + +/// +/// \brief Shorthand for ```is_floating_point::value``` +/// \tparam T type to check +template constexpr bool_t is_rvalue_reference_v = is_rvalue_reference {}; + + + +// 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 struct is_member_function_pointer + : bool_constant {}; + +/// +/// \brief Shorthand for ```is_member_function_pointer::value``` +/// \tparam T type to check +template constexpr bool_t is_member_function_pointer_v = is_member_function_pointer {}; + + + +// 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 struct is_member_object_pointer + : bool_constant {}; + +/// +/// \brief Shorthand for ```is_member_object_pointer::value``` +/// \tparam T type to check +template constexpr bool_t is_member_object_pointer_v = is_member_object_pointer {}; + + + +// 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 struct is_arithmetic + : bool_constant or is_floating_point_v>{}; + +/// +/// \brief Shorthand for ```is_arithmetic::value``` +/// \tparam T type to check +template constexpr bool_t is_arithmetic_v = is_arithmetic::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 struct is_fundamental + : bool_constant or is_void_v or is_null_pointer_v>{}; + +/// +/// \brief Shorthand for ```is_fundamental::value``` +/// \tparam T type to check +template constexpr bool_t is_fundamental_v = is_fundamental::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 struct is_scalar + : bool_constant or is_enum_v or is_pointer_v>{}; + +/// +/// \brief Shorthand for ```is_scalar::value``` +/// \tparam T type to check +template constexpr bool_t is_scalar_v = is_scalar::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 struct is_object : bool_constant {}; + +/// +/// \brief Shorthand for ```is_object::value``` +/// \tparam T type to check +template constexpr bool_t is_object_v = is_object::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 struct is_compound : bool_constant> {}; + +/// +/// \brief Shorthand for ```is_compound::value``` +/// \tparam T type to check +template constexpr bool_t is_compound_v = is_compound::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 struct is_reference + : detail::_is_reference{}; + +/// +/// \brief Shorthand for ```is_floating_point::value``` +/// \tparam T type to check +template constexpr bool_t is_reference_v = is_reference {}; + + + +// 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 struct is_member_pointer + : bool_constant {}; + +/// +/// \brief Shorthand for ```is_member_function_pointer::value``` +/// \tparam T type to check +template constexpr bool_t is_member_pointer_v = is_member_pointer {}; + + + +// fennec::is_trivial ================================================================================================== + +/// +/// \brief Check if type `T` is trivial +/// +/// \details Checks if `T` +/// \tparam T type to check +template struct is_trivial : bool_constant {}; + +/// +/// \brief Shorthand for `is_trivial::value` +/// \tparam T type to check +template constexpr bool_t is_trivial_v = is_trivial{}; + + + +// fennec::is_trivially_copyable ======================================================================================= + +/// +/// \brief Check if type `T` is trivially_copyable +/// +/// \details Checks if `T` +/// \tparam T type to check +template struct is_trivially_copyable : bool_constant {}; + +/// +/// \brief Shorthand for `is_trivially_copyable::value` +/// \tparam T type to check +template constexpr bool_t is_trivially_copyable_v = is_trivially_copyable{}; + + + +// fennec::is_standard_layout ========================================================================================== + +/// +/// \brief Check if type `T` is standard_layout +/// +/// \details Checks if `T` +/// \tparam T type to check +template struct is_standard_layout : bool_constant {}; + +/// +/// \brief Shorthand for `is_standard_layout::value` +/// \tparam T type to check +template constexpr bool_t is_standard_layout_v = is_standard_layout{}; + + + +// fennec::has_unique_object_representations =========================================================================== + +/// +/// \brief Check if type `T` has unique object representations +/// +/// \details Checks if `T` +/// \tparam T type to check +template struct has_unique_object_representations + : bool_constant)> {}; + +/// +/// \brief Shorthand for `has_unique_object_representations::value` +/// \tparam T type to check +template constexpr bool_t has_unique_object_representations_v = has_unique_object_representations{}; + + + +// fennec::is_empty ==================================================================================================== + +/// +/// \brief Check if type `T` is empty +/// +/// \details Checks if `T` +/// \tparam T type to check +template struct is_empty : bool_constant {}; + +/// +/// \brief Shorthand for `is_empty::value` +/// \tparam T type to check +template constexpr bool_t is_empty_v = is_empty{}; + + + +// fennec::is_polymorphic ============================================================================================== + +/// +/// \brief Check if type `T` is polymorphic +/// +/// \details Checks if `T` +/// \tparam T type to check +template struct is_polymorphic : bool_constant {}; + +/// +/// \brief Shorthand for `is_polymorphic::value` +/// \tparam T type to check +template constexpr bool_t is_polymorphic_v = is_polymorphic{}; + + + +// fennec::is_abstract ================================================================================================= + +/// +/// \brief Check if type `T` is abstract +/// +/// \details Checks if `T` +/// \tparam T type to check +template struct is_abstract : bool_constant {}; + +/// +/// \brief Shorthand for `is_abstract::value` +/// \tparam T type to check +template constexpr bool_t is_abstract_v = is_abstract{}; + + + +// fennec::is_complete ================================================================================================= + +/// +/// \brief Check if type `T` is complete +/// +/// \details Checks if `T` +/// \tparam T type to check +template struct is_complete : detail::_is_complete::type {}; + +/// +/// \brief Shorthand for `is_complete::value` +/// \tparam T type to check +template constexpr bool_t is_complete_v = is_complete{}; + + + +// fennec::is_final ================================================================================================= + +/// +/// \brief Check if type `T` is final +/// +/// \details Checks if `T` +/// \tparam T type to check +template struct is_final : bool_constant {}; + +/// +/// \brief Shorthand for `is_final::value` +/// \tparam T type to check +template constexpr bool_t is_final_v = is_final{}; + + + +// fennec::is_aggregate ================================================================================================= + +/// +/// \brief Check if type `T` is aggregate +/// +/// \details Checks if `T` +/// \tparam T type to check +template struct is_aggregate : bool_constant {}; + +/// +/// \brief Shorthand for `is_aggregate::value` +/// \tparam T type to check +template constexpr bool_t is_aggregate_v = is_aggregate{}; @@ -619,7 +986,7 @@ template constexpr bool_t is_integral_v = is_integral::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 struct is_signed - : detail::_is_signed> {}; + : detail::_is_signed> {}; /// /// \brief Shorthand for ```is_signed::value``` @@ -637,138 +1004,12 @@ template constexpr bool_t is_signed_v = is_signed::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 struct is_unsigned - : detail::_is_unsigned> {}; + : detail::_is_unsigned> {}; /// /// \brief Shorthand for ```is_unsigned::value``` /// \tparam T type to check -template constexpr bool_t is_unsigned_v = is_unsigned::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 struct is_floating_point - : detail::_is_floating_point>{}; - -/// -/// \brief Shorthand for ```is_floating_point::value``` -/// \tparam T type to check -template constexpr bool_t is_floating_point_v = is_floating_point {}; - - -// 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 struct is_pointer - : detail::_is_pointer>{}; - -/// -/// \brief Shorthand for ```is_pointer::value``` -/// \tparam T type to check -template constexpr bool_t is_pointer_v = is_pointer {}; - - -// 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 struct is_reference - : detail::_is_reference{}; - -/// -/// \brief Shorthand for ```is_floating_point::value``` -/// \tparam T type to check -template constexpr bool_t is_reference_v = 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 struct is_lvalue_reference - : detail::_is_lvalue_reference{}; - -/// -/// \brief Shorthand for ```is_floating_point::value``` -/// \tparam T type to check -template constexpr bool_t is_lvalue_reference_v = is_lvalue_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 struct is_rvalue_reference - : detail::_is_rvalue_reference{}; - -/// -/// \brief Shorthand for ```is_floating_point::value``` -/// \tparam T type to check -template constexpr bool_t is_rvalue_reference_v = is_rvalue_reference {}; - - - -// 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 struct is_arithmetic - : bool_constant or is_floating_point_v>{}; - -/// -/// \brief Shorthand for ```is_arithmetic::value``` -/// \tparam T type to check -template constexpr bool_t is_arithmetic_v = is_arithmetic::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 struct is_scalar - : bool_constant or is_enum_v or is_pointer_v>{}; - -/// -/// \brief Shorthand for ```is_scalar::value``` -/// \tparam T type to check -template constexpr bool_t is_scalar_v = is_scalar::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 struct is_fundamental - : bool_constant || is_void_v || is_null_pointer_v>{}; - -/// -/// \brief Shorthand for ```is_fundamental::value``` -/// \tparam T type to check -template constexpr bool_t is_fundamental_v = is_fundamental::value; + template constexpr bool_t is_unsigned_v = is_unsigned::value; // fennec::is_same ===================================================================================================== @@ -791,7 +1032,7 @@ template struct is_same : true_type {}; template constexpr bool_t is_same_v = is_same {}; -// fennec::is_base_of ===================================================================================================== +// fennec::is_base_of ================================================================================================== /// /// \brief Check if `Derived` has a base type of `Base` @@ -809,61 +1050,7 @@ template struct is_base_of : bool_constant< /// \tparam Derived derived type to check template constexpr bool_t is_base_of_v = is_base_of {}; -// fennec::is_complete ============================================================================================== -/// -/// \brief Check if type `T` is complete -/// -/// \details Checks if `T` -/// \tparam T type to check -template struct is_complete : detail::_is_complete::type {}; - -/// -/// \brief Shorthand for `is_complete::value` -/// \tparam T type to check -template constexpr bool_t is_complete_v = is_complete{}; - -// fennec::is_iterable ============================================================================================== - -/// -/// \brief Check if type `T` is iterable -/// -/// \details Checks if `T` -/// \tparam T type to check -template struct is_iterable : decltype(detail::_is_iterable(0)) {}; - -/// -/// \brief Shorthand for `is_iterable::value` -/// \tparam T type to check -template constexpr bool_t is_iterable_v = is_iterable{}; - -// fennec::is_indexable ============================================================================================== - -/// -/// \brief Check if type `T` is indexable -/// -/// \details Checks if `T` -/// \tparam T type to check -template struct is_indexable : decltype(detail::_is_indexable(0)) {}; - -/// -/// \brief Shorthand for `is_indexable::value` -/// \tparam T type to check -template constexpr bool_t is_indexable_v = is_indexable{}; - -// fennec::is_mappable ============================================================================================== - -/// -/// \brief Check if type `T` is mappable -/// -/// \details Checks if `T` -/// \tparam T type to check -template struct is_mappable : decltype(detail::_is_mappable(0)) {}; - -/// -/// \brief Shorthand for `is_mappable::value` -/// \tparam T type to check -template constexpr bool_t is_mappable_v = is_mappable{}; // fennec::is_convertible ============================================================================================== @@ -883,6 +1070,7 @@ template struct is_convertible template constexpr bool_t is_convertible_v = is_convertible{}; + // fennec::is_constructible ============================================================================================ /// @@ -899,6 +1087,8 @@ template 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 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 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 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 struct is_move_constructible : bool_constant)> {}; @@ -946,42 +1142,6 @@ template struct is_move_constructible template constexpr bool_t is_move_constructible_v = is_move_constructible{}; -// fennec::is_destructible =================================================================================== - -/// -/// \brief Check if `ClassT` is destructible -/// \tparam ClassT The class type to test -template struct is_destructible - : detail::_is_destructible::type {}; - -/// -/// \brief Shorthand for `is_destructible::value` -template constexpr bool_t is_destructible_v = is_destructible{}; - - - -/// -/// \brief Check if `ClassT` is trivially destructible -/// \tparam ClassT The class type to test -template struct is_trivially_destructible - : bool_constant {}; - -/// -/// \brief Shorthand for `is_trivially_destructible::value` -template constexpr bool_t is_trivially_destructible_v = is_trivially_destructible{}; - - - -/// -/// \brief Check if `ClassT` is nothrow destructible -/// \tparam ClassT The class type to test -template struct is_nothrow_destructible - : detail::_is_nothrow_destructible::type {}; - -/// -/// \brief Shorthand for `is_nothrow_destructible::value` -template constexpr bool_t is_nothrow_destructible_v = is_nothrow_destructible{}; - // fennec::is_assignable =============================================================================================== @@ -998,6 +1158,7 @@ template struct is_assignable template constexpr bool_t is_assignable_v = is_assignable{}; + // fennec::is_copy_assignable ========================================================================================== /// @@ -1011,6 +1172,7 @@ template struct is_copy_assignable template constexpr bool_t is_copy_assignable_v = is_copy_assignable{}; + // fennec::is_move_assignable ========================================================================================== /// @@ -1024,6 +1186,96 @@ template struct is_move_assignable template constexpr bool_t is_move_assignable_v = is_move_assignable{}; + +// fennec::is_destructible ============================================================================================= + +/// +/// \brief Check if `ClassT` is destructible +/// \tparam ClassT The class type to test +template struct is_destructible + : detail::_is_destructible::type {}; + +/// +/// \brief Shorthand for `is_destructible::value` +template constexpr bool_t is_destructible_v = is_destructible{}; + + + +// fennec::is_trivially_destructible =================================================================================== + +/// +/// \brief Check if `ClassT` is trivially destructible +/// \tparam ClassT The class type to test +template struct is_trivially_destructible + : bool_constant {}; + +/// +/// \brief Shorthand for `is_trivially_destructible::value` +template constexpr bool_t is_trivially_destructible_v = is_trivially_destructible{}; + + + +// fennec::is_nothrow_destructible ===================================================================================== + +/// +/// \brief Check if `ClassT` is nothrow destructible +/// \tparam ClassT The class type to test +template struct is_nothrow_destructible + : detail::_is_nothrow_destructible::type {}; + +/// +/// \brief Shorthand for `is_nothrow_destructible::value` +template constexpr bool_t is_nothrow_destructible_v = is_nothrow_destructible{}; + + + +// fennec::is_iterable ================================================================================================= + +/// +/// \brief Check if type `T` is iterable +/// +/// \details Checks if `T` +/// \tparam T type to check +template struct is_iterable : decltype(detail::_is_iterable(0)) {}; + +/// +/// \brief Shorthand for `is_iterable::value` +/// \tparam T type to check +template constexpr bool_t is_iterable_v = is_iterable{}; + + + +// fennec::is_indexable ================================================================================================ + +/// +/// \brief Check if type `T` is indexable +/// +/// \details Checks if `T` +/// \tparam T type to check +template struct is_indexable : decltype(detail::_is_indexable(0)) {}; + +/// +/// \brief Shorthand for `is_indexable::value` +/// \tparam T type to check +template constexpr bool_t is_indexable_v = is_indexable{}; + + + +// fennec::is_mappable ================================================================================================= + +/// +/// \brief Check if type `T` is mappable +/// +/// \details Checks if `T` +/// \tparam T type to check +template struct is_mappable : decltype(detail::_is_mappable(0)) {}; + +/// +/// \brief Shorthand for `is_mappable::value` +/// \tparam T type to check +template constexpr bool_t is_mappable_v = is_mappable{}; + + } #endif // FENNEC_LANG_TYPE_TRAITS_H diff --git a/include/fennec/lang/type_transforms.h b/include/fennec/lang/type_transforms.h index 8c82c17..54ab14e 100644 --- a/include/fennec/lang/type_transforms.h +++ b/include/fennec/lang/type_transforms.h @@ -127,6 +127,12 @@ namespace fennec { +// Decay Conversions =================================================================================================== + +template struct decay : detail::_decay {}; + +template using decay_t = typename decay::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 struct add_pointer : type_identity{}; +template struct add_pointer : detail::_add_pointer{}; /// /// \brief shorthand for `typename add_pointer::type` @@ -146,10 +152,7 @@ template using add_pointer_t = typename add_pointer::type; /// /// \details removes a pointer from the provided type such that `T*` becomes `T` /// \tparam T Resultant Type -template struct remove_pointer : type_identity {}; - -// specialization for T* -template struct remove_pointer : type_identity {}; +template struct remove_pointer : detail::_remove_pointer {}; /// /// \brief shorthand for `typename remove_pointer::type` @@ -235,30 +238,24 @@ template 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 struct add_const : type_identity {}; +template struct add_const : detail::_add_const {}; /// /// \brief shorthand for `typename add_const::type` template using add_const_t = typename add_const::type; -// specialization for const types -template struct add_const : type_identity {}; - /// /// \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 struct remove_const : type_identity {}; +template struct remove_const : detail::_remove_const {}; /// /// \brief shorthand for `typename remove_const::type` template using remove_const_t = typename remove_const::type; -// specialization for const types -template struct remove_const : type_identity {}; - /// @@ -266,30 +263,24 @@ template struct remove_const : type_identity {}; /// /// \details removes references from the provided type such that `T` becomes `volatile T` /// \tparam T Reference Type -template struct add_volatile : type_identity {}; +template struct add_volatile : detail::_add_volatile {}; /// /// \brief shorthand for `typename add_volatile::type` template using add_volatile_t = typename add_volatile::type; -// specialization for volatile types -template struct add_volatile : type_identity {}; - /// /// \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 struct remove_volatile : type_identity {}; +template struct remove_volatile : detail::_remove_volatile {}; /// /// \brief shorthand for `typename remove_volatile::type` template using remove_volatile_t = typename remove_volatile::type; -// specialization for volatile types -template struct remove_volatile : type_identity {}; - /// @@ -298,21 +289,12 @@ template struct remove_volatile : type_identity {}; /// \details removes references from the provided type such that `T`, `const T`, and `volatile T` become /// `const volatile T` /// \tparam T Reference Type -template struct add_cv : type_identity {}; +template struct add_cv : detail::_add_cv {}; /// /// \brief shorthand for `typename add_cv::type` template using add_cv_t = typename add_cv::type; -// specialization for const types -template struct add_cv : type_identity {}; - -// specialization for volatile types -template struct add_cv : type_identity {}; - -// specialization for const volatile types -template struct add_cv : type_identity {}; - /// @@ -321,16 +303,7 @@ template struct add_cv : type_identity struct remove_cv : type_identity {}; - -// specialization for const types -template struct remove_cv : type_identity {}; - -// specialization for volatile types -template struct remove_cv : type_identity {}; - -// specialization for const volatile types -template struct remove_cv : type_identity {}; +template struct remove_cv : detail::_remove_cv {}; /// /// \brief shorthand for `typename remove_cv::type` @@ -343,11 +316,11 @@ template using remove_cv_t = typename remove_cv::type; /// /// \details adds references and const volatile qualifiers to the provided type. /// \tparam T Reference Type -template struct add_cvr : type_identity>> {}; +template struct add_cvref : type_identity>> {}; /// /// \brief shorthand for `typename add_cvr::type` -template using add_cvr_t = typename add_cvr::type; +template using add_cvref_t = typename add_cvref::type; @@ -356,12 +329,12 @@ template using add_cvr_t = typename add_cvr::type; /// /// \details removes const and volatile from the provided type such that /// \tparam T Reference Type -template struct remove_cvr : type_identity>> {}; +template struct remove_cvref : type_identity>> {}; /// /// \brief shorthand for `typename remove_cvr::type` -template using remove_cvr_t = typename remove_cvr::type; +template using remove_cvref_t = typename remove_cvref::type; @@ -370,12 +343,12 @@ template using remove_cvr_t = typename remove_cvr::type; /// /// \details removes const and volatile from the provided type such that /// \tparam T Reference Type -template struct remove_cvrp : type_identity>>> {}; +template struct remove_cvrefptr : type_identity>>> {}; /// /// \brief shorthand for `typename remove_cvrp_t::type` -template using remove_cvrp_t = typename remove_cvrp::type; +template using remove_cvrefptr_t = typename remove_cvrefptr::type; } diff --git a/include/fennec/math/vector_traits.h b/include/fennec/math/vector_traits.h index e2b58c2..45f2cbc 100644 --- a/include/fennec/math/vector_traits.h +++ b/include/fennec/math/vector_traits.h @@ -71,7 +71,7 @@ namespace fennec /// /// \brief check if \p T is a fennec::vector type /// \tparam T type to check -template struct is_vector : detail::_is_vector_helper>{}; +template struct is_vector : detail::_is_vector_helper>{}; /// /// \brief shorthand for ```is_vector::value``` @@ -81,7 +81,7 @@ template constexpr bool is_vector_v = is_vector::value; /// /// \brief Get the number of Components in \p T, returns 1 for types that pass ```is_arithmetic```, returns \ref vector::N for \ref vector "Vector" Types, and returns 0 for all other cases /// \tparam T type to check -template struct component_count : detail::_component_count_helper>{}; +template struct component_count : detail::_component_count_helper>{}; /// /// \brief shorthand for ```component_count::value``` diff --git a/include/fennec/memory/pointers.h b/include/fennec/memory/pointers.h index edbbdf4..b355ff6 100644 --- a/include/fennec/memory/pointers.h +++ b/include/fennec/memory/pointers.h @@ -20,6 +20,7 @@ #define FENNEC_MEMORY_POINTERS_H #include +#include namespace fennec { @@ -176,6 +177,10 @@ public: return _handle; } + operator bool() const { + return _handle != nullptr; + } + private: delete_t _delete; diff --git a/include/fennec/platform/interface/display_server.h b/include/fennec/platform/interface/display_server.h index 7f1bfbd..3100711 100644 --- a/include/fennec/platform/interface/display_server.h +++ b/include/fennec/platform/interface/display_server.h @@ -94,10 +94,7 @@ enum feature_ : uint32_t { using featureset_t = bitfield; using window_id = uint32_t; - using window_pool = object_pool; - - struct config { - }; + using window_pool = object_pool>; // 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 gfx_context; FENNEC_RTTI_CLASS_ENABLE() { diff --git a/include/fennec/platform/interface/platform.h b/include/fennec/platform/interface/platform.h index e179a7f..b906384 100644 --- a/include/fennec/platform/interface/platform.h +++ b/include/fennec/platform/interface/platform.h @@ -19,9 +19,10 @@ #ifndef FENNEC_PLATFORM_INTERFACE_PLATFORM_H #define FENNEC_PLATFORM_INTERFACE_PLATFORM_H -#include #include +#include + #include #include #include @@ -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; + unique_ptr wmanager; FENNEC_RTTI_CLASS_ENABLE() { } diff --git a/include/fennec/platform/interface/window.h b/include/fennec/platform/interface/window.h index 51f6081..b5330ac 100644 --- a/include/fennec/platform/interface/window.h +++ b/include/fennec/platform/interface/window.h @@ -39,6 +39,7 @@ #include #include +#include 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 gfx_surface; }; template 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; diff --git a/include/fennec/platform/linux/wayland/server.h b/include/fennec/platform/linux/wayland/server.h index daee9fe..f36cc29 100644 --- a/include/fennec/platform/linux/wayland/server.h +++ b/include/fennec/platform/linux/wayland/server.h @@ -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; } diff --git a/include/fennec/platform/linux/wayland/window.h b/include/fennec/platform/linux/wayland/window.h index f7be543..94b131d 100644 --- a/include/fennec/platform/linux/wayland/window.h +++ b/include/fennec/platform/linux/wayland/window.h @@ -50,7 +50,7 @@ namespace fennec class wayland_window : public window_base { 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; diff --git a/include/fennec/platform/window_manager.cpp b/include/fennec/platform/window_manager.cpp new file mode 100644 index 0000000..af03744 --- /dev/null +++ b/include/fennec/platform/window_manager.cpp @@ -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 . +// ===================================================================================================================== + + +#include + +#include +#include +#include +#include + +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 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 \ No newline at end of file diff --git a/include/fennec/platform/window_manager.h b/include/fennec/platform/window_manager.h index 84cc203..6119f07 100644 --- a/include/fennec/platform/window_manager.h +++ b/include/fennec/platform/window_manager.h @@ -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 + +#include +#include +#include namespace fennec { -/// -/// \brief Thread-Safe wrapper for `display_server` and `window` class window_manager { +// Definitions ========================================================================================================= +private: + using server_t = unique_ptr; + using window_t = unique_ptr; + using window_pool_t = object_pool; + + +// 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 \ No newline at end of file +#endif // FENNEC_PLATFORM_WINDOWMANAGER_H \ No newline at end of file diff --git a/include/fennec/rtti/forward.h b/include/fennec/rtti/forward.h index 4ec1fc4..b72b554 100644 --- a/include/fennec/rtti/forward.h +++ b/include/fennec/rtti/forward.h @@ -34,7 +34,6 @@ namespace fennec { -class function; struct vtypelist; template struct typelist; diff --git a/include/fennec/rtti/type_data.h b/include/fennec/rtti/type_data.h index adfdb42..10a532b 100644 --- a/include/fennec/rtti/type_data.h +++ b/include/fennec/rtti/type_data.h @@ -78,7 +78,7 @@ private: template static unique_ptr _make_data() { - using raw_t = remove_cvrp_t; + using raw_t = remove_cvrefptr_t; using supers_t = detect_t, _super_class_list, T>; auto res = fennec::unique_ptr(new type_data{ diff --git a/include/fennec/rtti/type_registry.h b/include/fennec/rtti/type_registry.h index 4203d3c..8a0878c 100644 --- a/include/fennec/rtti/type_registry.h +++ b/include/fennec/rtti/type_registry.h @@ -43,7 +43,7 @@ namespace fennec template 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 - static BaseT* _constructor_helper(ArgsT&&...args) { - return new T(fennec::forward(args)...); + static BaseT* _constructor_helper(ArgsT...args) { + return new T(args...); } }; diff --git a/include/fennec/threading/atomic.h b/include/fennec/threading/atomic.h new file mode 100644 index 0000000..f6e00de --- /dev/null +++ b/include/fennec/threading/atomic.h @@ -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 . +// ===================================================================================================================== + +/// +/// \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 + +#include + +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 +struct atomic { + +// Assertions ========================================================================================================== +public: + static_assert(is_integral_v, "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(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 \ No newline at end of file diff --git a/include/fennec/threading/detail/_atomic.h b/include/fennec/threading/detail/_atomic.h new file mode 100644 index 0000000..f782b02 --- /dev/null +++ b/include/fennec/threading/detail/_atomic.h @@ -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 . +// ===================================================================================================================== + +#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 +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 +constexpr T atomic_load(_Atomic T* x) { + return ::__atomic_load_n(x, memory_order_seq_cst); +} + +template +constexpr T atomic_load_explicit(_Atomic T* x, memory_order memorder) { + return ::__atomic_load_n(x, memorder); +} + + + +// atomic_store ======================================================================================================== + +template +constexpr bool atomic_store(_Atomic T* x, const T val) { + return ::__atomic_store_n(x, val, memory_order_seq_cst); +} + +template +constexpr bool atomic_store_explicit(_Atomic T* x, const T val, memory_order memorder) { + return ::__atomic_store_n(x, val, memorder); +} + + + +// atomic_exchange ===================================================================================================== + +template +constexpr bool atomic_exchange(_Atomic T* x, const T val) { + return ::__atomic_exchange_n(x, val, memory_order_seq_cst); +} + +template +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 +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 +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 +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 +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 +constexpr T atomic_fetch_add(_Atomic T* x, const T val) { + return ::__atomic_fetch_add(x, val, memory_order_seq_cst); +} + +template +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 +constexpr T atomic_fetch_sub(_Atomic T* x, const T val) { + return ::__atomic_fetch_sub(x, val, memory_order_seq_cst); +} + +template +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 +constexpr T atomic_fetch_or(_Atomic T* x, const T val) { + return ::__atomic_fetch_or(x, val, memory_order_seq_cst); +} + +template +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 +constexpr T atomic_fetch_xor(_Atomic T* x, const T val) { + return ::__atomic_fetch_xor(x, val, memory_order_seq_cst); +} + +template +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 +constexpr T atomic_fetch_and(_Atomic T* x, const T val) { + return ::__atomic_fetch_and(x, val, memory_order_seq_cst); +} + +template +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 diff --git a/include/fennec/threading/detail/_thread.h b/include/fennec/threading/detail/_thread.h new file mode 100644 index 0000000..59b7c88 --- /dev/null +++ b/include/fennec/threading/detail/_thread.h @@ -0,0 +1,59 @@ +// ===================================================================================================================== +// fennec, a free and open source game engine +// Copyright © 2025 Medusa Slockbower +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// ===================================================================================================================== + +/// +/// \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 +#include +#include + +namespace fennec::detail +{ + +template using thread_proxy_t = tuple; + +template +void _execute_thread(thread_proxy_t, ArgsT...>& data, index_metasequence) { + auto func = data.template get<0>(); + func(fennec::move(data.template get()) ...); +} + +template +void* _run_thread(void* data) { + unique_ptr ptr(data); + detail::_execute_thread(*ptr, make_index_metasequence_t{}); + return nullptr; +} + +} + +#endif // FENNEC_THREADING_DETAIL_THREAD_H \ No newline at end of file diff --git a/include/fennec/threading/thread.h b/include/fennec/threading/thread.h new file mode 100644 index 0000000..1294313 --- /dev/null +++ b/include/fennec/threading/thread.h @@ -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 . +// ===================================================================================================================== + +/// +/// \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 +#include +#include +#include +#include +#include + +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; + friend struct formatter; + + 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 + requires(not is_same_v>) + thread(FuncT&& func, ArgsT&&...args) + : _handle(nullthread) { + using proxy_t = detail::thread_proxy_t, ArgsT...>; + unique_ptr proxy = fennec::make_unique(fennec::forward(func), fennec::forward(args)...); + + int_t res = ::pthread_create(&_handle, nullptr, &detail::_run_thread(), 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 { + size_t operator()(thread::id v) const noexcept { + return hash()(v._id); + } +}; + +template<> +struct formatter { + string operator()(const format_arg& fmt, thread::id v) const noexcept { + return formatter()(fmt, v._id); + } +}; + +} + +#endif // FENNEC_THREADING_THREAD_H \ No newline at end of file diff --git a/source/filesystem/file.cpp b/source/filesystem/file.cpp index e6c6280..a2c17b0 100644 --- a/source/filesystem/file.cpp +++ b/source/filesystem/file.cpp @@ -1047,6 +1047,7 @@ void file::println(const cstring& str) { void file::println(const string& str) { write(str.data(), str.length()); + putc('\n'); } bool file::putc(char c) { diff --git a/source/platform/interface/platform.cpp b/source/platform/interface/platform.cpp index edf3eb7..c5f30af 100644 --- a/source/platform/interface/platform.cpp +++ b/source/platform/interface/platform.cpp @@ -29,25 +29,22 @@ platform::platform() { } void platform::initialize() { + if (wmanager) { + return; + } + logger::log(format("Initializing platform {}", get_type().name())); - display_server::entrylist_t display_servers = display_server::get_type_list(); - while (not display_servers.empty()) { - display_server::entry it = display_servers.front(); - display_servers.pop(); - - unique_ptr server = unique_ptr(it.ctor(this)); - server->connect(); - if (server->connected()) { - logger::log(format("Selected {} for the display server.", server->get_type().name())); - display = move(server); - break; - } - } + // Setup Window Manager + wmanager = make_unique(this); + wmanager->initialize(); } void platform::shutdown() { - display.reset(); + + // Cleanup Window Manager + wmanager->shutdown(); + wmanager.reset(); } } diff --git a/source/platform/interface/window.cpp b/source/platform/interface/window.cpp index 6713043..b7ea1c4 100644 --- a/source/platform/interface/window.cpp +++ b/source/platform/interface/window.cpp @@ -29,14 +29,20 @@ /// #include -#include #include +#include namespace fennec { -window* window::get_parent() const { - return server->get_window(cfg.parent); +window::window(display_server* server, const config& conf, window* parent) + : server(server), parent(parent) + , cfg(conf), state(), root(nullptr) { + state.mode = conf.mode; +} + +window::~window() { + } void window::begin_frame() { diff --git a/source/platform/linux/wayland/server.cpp b/source/platform/linux/wayland/server.cpp index e23e80a..39932e4 100644 --- a/source/platform/linux/wayland/server.cpp +++ b/source/platform/linux/wayland/server.cpp @@ -177,9 +177,8 @@ void wayland_server::dispatch() { } } -window* wayland_server::create_window(const window::config& conf) { - size_t id = windows.insert(new wayland_window(this, windows.next_id(), conf)); - return windows[id]; +window* wayland_server::create_window(const window::config& conf, window* parent) { + return new wayland_window(this, conf, parent); } void wayland_server::_wl_registry_listen_global(void* data, wl_registry* reg, uint32_t id, const char* name, uint32_t version) { diff --git a/source/platform/linux/wayland/window.cpp b/source/platform/linux/wayland/window.cpp index 3fb2235..baee6b2 100644 --- a/source/platform/linux/wayland/window.cpp +++ b/source/platform/linux/wayland/window.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -27,7 +28,6 @@ #include #include #include -#include #if FENNEC_HAS_LIBDECOR #include @@ -35,11 +35,10 @@ using namespace fennec; -wayland_window::wayland_window(display_server* server, uint32_t id, const config& cfg) - : window_base(server, id, cfg) +wayland_window::wayland_window(display_server* server, const config& cfg, window* parent) + : window_base(server, cfg, parent) , surface(nullptr) , xdgsurface(nullptr) { - } wayland_window::~wayland_window() { @@ -79,7 +78,7 @@ void wayland_window::initialize() { } - wayland_window* root = this; + root = parent; while (root != nullptr and root->is_popup()) { root = static_cast(root->get_parent()); } @@ -110,7 +109,7 @@ void wayland_window::initialize() { .reserved9 = nullptr, }; - gfx_surface = wl_server->get_gfx_context()->create_surface(this); + gfx_surface = unique_ptr(wl_server->get_gfx_context()->create_surface(this)); if (wl_server->has_libdecor) { @@ -151,11 +150,6 @@ void wayland_window::shutdown() { wayland_server* wl_server = static_cast(server); - if (frame_callback) { - wl_callback_destroy(frame_callback); - frame_callback = nullptr; - } - #if FENNEC_HAS_LIBDECOR if (libdecorframe) { libdecor_frame_unref(libdecorframe); @@ -164,6 +158,15 @@ void wayland_window::shutdown() { } #endif + if (gfx_surface) { + gfx_surface.reset(); + } + + if (frame_callback) { + wl_callback_destroy(frame_callback); + frame_callback = nullptr; + } + if (xdgtoplevel) { xdg_toplevel_destroy(xdgtoplevel); xdgtoplevel = nullptr; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ca0d23a..1110d8b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -7,6 +7,8 @@ set(CMAKE_C_STANDARD 23) add_executable(fennec-test main.cpp tests/lang/test_metaprogramming.h + tests/lang/test_function.h + tests/test_threading.h ) target_compile_definitions(fennec-test PUBLIC FENNEC_TEST_CWD="${CMAKE_SOURCE_DIR}/bin/${FENNEC_BUILD_NAME}" diff --git a/test/main.cpp b/test/main.cpp index f6bd6cc..fde4b65 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -27,6 +27,7 @@ #include "tests/test_filesystem.h" #include "tests/test_platform.h" #include "tests/test_rtti.h" +#include "tests/test_threading.h" int main(int, char **) { @@ -66,9 +67,9 @@ int main(int, char **) fennec::test::fennec_test_filesystem(); fennec_test_spacer(3); - fennec_test_header("platform library"); + fennec_test_header("threading"); fennec_test_spacer(2); - fennec::test::fennec_test_platform(); + fennec::test::fennec_test_threading(); fennec_test_spacer(3); fennec_test_header("rtti library"); @@ -76,5 +77,10 @@ int main(int, char **) fennec::test::fennec_test_rtti(); fennec_test_spacer(3); + fennec_test_header("platform library"); + fennec_test_spacer(2); + fennec::test::fennec_test_platform(); + fennec_test_spacer(3); + return 0; } diff --git a/test/tests/lang/test_function.h b/test/tests/lang/test_function.h new file mode 100644 index 0000000..9893c70 --- /dev/null +++ b/test/tests/lang/test_function.h @@ -0,0 +1,64 @@ +// ===================================================================================================================== +// fennec, a free and open source game engine +// Copyright © 2025 Medusa Slockbower +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// ===================================================================================================================== + +/// +/// \file test_function.h +/// \brief +/// +/// +/// \details +/// \author Medusa Slockbower +/// +/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html)) +/// +/// + + +#ifndef FENNEC_TEST_LANG_FUNCTION_H +#define FENNEC_TEST_LANG_FUNCTION_H + +#include "../../test.h" + +#include + +namespace fennec::test +{ + +inline bool fennec_test_lang_function_test() { + return true; +} + +inline void fennec_test_lang_function() { + function test; + + fennec_test_run((bool)(test = fennec_test_lang_function_test), true); + fennec_test_run(test(), true); + + fennec_test_spacer(1); + + fennec_test_run((bool)(test = []() { return true; }), true); + fennec_test_run(test(), true); + + fennec_test_spacer(1); + + fennec_test_run((bool)(test = nullptr), false); +} + +} + +#endif // FENNEC_TEST_LANG_FUNCTION_H \ No newline at end of file diff --git a/test/tests/test_lang.h b/test/tests/test_lang.h index 146ce20..eadcb70 100644 --- a/test/tests/test_lang.h +++ b/test/tests/test_lang.h @@ -21,6 +21,7 @@ #include "lang/test_bits.h" #include "lang/test_conditional_types.h" +#include "lang/test_function.h" #include "lang/test_hashing.h" #include "lang/test_metaprogramming.h" @@ -41,6 +42,11 @@ namespace fennec::test fennec_test_subheader("metaprogramming tests"); fennec_test_spacer(2); fennec_test_lang_metaprogramming(); + fennec_test_spacer(3); + + fennec_test_subheader("function tests"); + fennec_test_spacer(2); + fennec_test_lang_function(); // TODO } diff --git a/test/tests/test_platform.h b/test/tests/test_platform.h index 7ef929b..e2c2b46 100644 --- a/test/tests/test_platform.h +++ b/test/tests/test_platform.h @@ -32,6 +32,7 @@ inline void fennec_test_platform() { platform* platform = platform::instance(); platform->initialize(); + /* display_server* display = platform->get_display_server(); window* window = display->create_window(window::config { @@ -59,8 +60,7 @@ inline void fennec_test_platform() { } window->shutdown(); - - delete window; + */ platform::instance()->shutdown(); diff --git a/test/tests/test_threading.h b/test/tests/test_threading.h new file mode 100644 index 0000000..3e641e4 --- /dev/null +++ b/test/tests/test_threading.h @@ -0,0 +1,48 @@ +// ===================================================================================================================== +// fennec, a free and open source game engine +// Copyright © 2025 Medusa Slockbower +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// ===================================================================================================================== + +/// +/// \file test_threading.h +/// \brief +/// +/// +/// \details +/// \author Medusa Slockbower +/// +/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html)) +/// +/// + + +#ifndef FENNEC_TEST_THREADING_H +#define FENNEC_TEST_THREADING_H + +#include + +namespace fennec::test +{ + +inline void fennec_test_threading() { + + atomic test; + +} + +} + +#endif // FENNEC_TEST_THREADING_H \ No newline at end of file