diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e4ada3..d78c8dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,6 +113,7 @@ add_library(fennec STATIC include/fennec/containers/bitfield.h include/fennec/containers/deque.h include/fennec/containers/dynarray.h + include/fennec/containers/generic.h include/fennec/containers/graph.h include/fennec/containers/initializer_list.h include/fennec/containers/list.h @@ -176,6 +177,8 @@ add_library(fennec STATIC include/fennec/rtti/enable.h include/fennec/rtti/forward.h include/fennec/rtti/typelist.h + include/fennec/rtti/type_registry.h + include/fennec/rtti/singleton.h include/fennec/rtti/detail/_constants.h diff --git a/cmake/gcc.cmake b/cmake/gcc.cmake index 4008a70..9ef7621 100644 --- a/cmake/gcc.cmake +++ b/cmake/gcc.cmake @@ -27,5 +27,4 @@ fennec_add_definitions( FENNEC_COMPILER_GCC=1 FENNEC_NO_INLINE=[[gnu::noinline]] FENNEC_FUNCTION_NAME=__PRETTY_FUNCTION__ - RYU_ONLY_64_BIT_OPS ) diff --git a/include/fennec/containers/generic.h b/include/fennec/containers/generic.h new file mode 100644 index 0000000..e953ebc --- /dev/null +++ b/include/fennec/containers/generic.h @@ -0,0 +1,210 @@ +// ===================================================================================================================== +// 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 universal.h +/// \brief +/// +/// +/// \details +/// \author Medusa Slockbower +/// +/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html)) +/// +/// + +#ifndef FENNEC_CONTAINERS_GENERIC_H +#define FENNEC_CONTAINERS_GENERIC_H + +#include +#include + +namespace fennec +{ + +/// +/// \brief A struct capable of holding a single object of any type +struct generic { + +// Definitions ========================================================================================================= +private: + + // based on GCC + enum op_ : uint8_t { + op_clone, + op_destroy, + op_type, + }; + + using manager_t = void* (*)(uint8_t, void*); + + +// Constructors ======================================================================================================== +public: + + /// + /// \brief Default Constructor + generic() + : _handle(nullptr) + , _manage(nullptr) { + } + + /// + /// \brief Copy Constructor + /// \param gen The generic object to copy + generic(const generic& gen) + : _handle(nullptr) + , _manage(gen._manage) { + if (_manage) { + _handle = _manage(op_clone, gen._handle); + } + } + + /// + /// \brief Move Constructor + /// \param gen The generic object to move + generic(generic&& gen) + : _handle(gen._handle) + , _manage(gen._manage) { + gen._handle = nullptr; + gen._manage = nullptr; + } + + /// + /// \brief Value Constructor + /// \tparam T The type of the value + /// \param x The value + template + generic(T&& x) + : _handle(new T(fennec::forward(x))) + , _manage(_manage_impl) { + } + + /// + /// \brief Emplace Constructor + /// \tparam T The type to construct + /// \tparam ArgsT The argument types + /// \param args The argument values + template + generic(type_identity, ArgsT&&...args) + : _handle(new T(fennec::forward(args)...)) + , _manage(_manage_impl) { + } + + /// + /// \brief Destructor + ~generic() { + reset(); + } + + +// Properties ========================================================================================================== + + type type() const { + return *static_cast(_manage(op_type, nullptr)); + } + + bool has_value() const { + return _handle != nullptr; + } + + +// Assignment ========================================================================================================== + + generic& operator=(const generic& gen) { + if (this == &gen) { // self-assignment case + return *this; + } + + reset(); + _manage = gen._manage; + _handle = _manage(op_clone, gen._handle); + return *this; + } + + generic& operator=(generic&& gen) noexcept { + swap(gen); + return *this; + } + + +// Utility ============================================================================================================= + + template + generic& operator=(T&& x) { + reset(); + _handle = new T(fennec::forward(x)); + _manage = _manage_impl(); + return *this; + } + + template + void emplace(ArgsT&&...args) { + reset(); + _handle = new T(fennec::forward(args)...); + _manage = _manage_impl; + } + + void reset() { + if (_manage) { + _handle = _manage(op_destroy, _handle); + _manage = nullptr; + } + } + + void swap(generic& gen) noexcept { + fennec::swap(_handle, gen._handle); + fennec::swap(_manage, gen._manage); + } + + template + T& cast() { + return *static_cast(_handle); + } + + template + const T& cast() const { + return *static_cast(_handle); + } + +private: + void* _handle; + manager_t _manage; + + template + static void* _manage_impl(uint8_t op, void* hnd) { + static fennec::type t = type::get(); + T* ptr = hnd; + + switch (op) { + case op_clone: + return new T(*ptr); + case op_destroy: + delete ptr; + return nullptr; + case op_type: + return &t; + default: + return nullptr; + } + } +}; + +} + +#endif // FENNEC_CONTAINERS_GENERIC_H \ No newline at end of file diff --git a/include/fennec/containers/variant.h b/include/fennec/containers/variant.h index 31b280e..270b94e 100644 --- a/include/fennec/containers/variant.h +++ b/include/fennec/containers/variant.h @@ -31,4 +31,216 @@ #ifndef FENNEC_CONTAINERS_VARIANT_H #define FENNEC_CONTAINERS_VARIANT_H +#include +#include +#include +#include + +namespace fennec +{ + +/// +/// \brief A structure that represents a union between `TypesT...` +/// \tparam TypesT The types to hold in the variant +template +struct variant { +// Assertions ========================================================================================================== + + static_assert( + is_unique_v and // No two types in TypesT... may be equivalent + not (is_reference_v or ...) and // No type in TypesT... may be a reference + not (is_array_v or ...) and // No type in TypesT... may be an array + not (is_void_v or ...) // No type in TypesT... may be void + ); + + +// Typedefs & Constants ================================================================================================ + + static constexpr size_t size = max_element_size_v; + static constexpr size_t nulltype = sizeof...(TypesT); + + + + +// Constructors ======================================================================================================== + + /// + /// \brief Default Constructor, constructs the first type in `TypesT...` that is default constructible + variant() + : _bytes {} + , _type(nulltype) { + using construct_t = search_element_t; + fennec::construct(_handle); + } + + /// + /// \brief Conversion Constructor, constructs the type in `TypesT...` that is identical to `T` + /// or the first that is constructible with `T` + /// \tparam T The type of the value + /// \param t The value to forward + template + variant(T&& t) + : _bytes {} + , _type() { + using same_t = search_element_args, TypesT...>; + using convert_t = search_element_args, TypesT...>; + using construct_t = conditional_t, convert_t, convert_t>; + fennec::construct(_handle, fennec::forward(t)); + } + + /// + /// \brief Emplace Constructor, constructs the first type in `TypesT...` that is constructible with `ArgsT...` + /// \tparam ArgsT The arguments of the constructor + /// \param args The argument values + template + variant(type_identity, ArgsT&&...args) + : _bytes{} + , _type(nulltype) { + static_assert(contains_element_v, "T must be in TypesT..."); + fennec::construct(_handle, fennec::forward(args)...); + _type = find_element_v; + } + + /// + /// \brief Copy Constructor + /// \param v The variant to copy + variant(const variant& v) + : _bytes {} + , _type(nulltype) { + + if (v._type == nulltype) { + return; + } + + ((v._type == find_element_v ? + fennec::construct(_handle, v.get()) : + (0) + ), ...); + _type = v._type; + } + + /// + /// \brief Move Constructor + /// \param v The variant to move + variant(variant&& v) noexcept + : _bytes {} + , _type() { + + if (v._type == nulltype) { + return; + } + + ((v._type == find_element_v ? + fennec::construct(_handle, fennec::move(v.get())) : + (0) + ), ...); + _type = v._type; + } + + /// + /// \brief Destructor, if a type is held, destruct it. + ~variant() { + _clear(); + } + + +// Assignment ========================================================================================================== + + template + variant& operator=(T&& t) { + + // First, check if `T` is in `TypesT...` + if constexpr((contains_element_v or ...)) { + using type_t = remove_reference_t; + if (_type == find_element_v) { + *static_cast(_handle) = fennec::forward(t); + } else { + _clear(); + fennec::construct(_handle, fennec::forward(t)); + _type = find_element_v; + } + return *this; + } + + // Next, try to assign using the currently held type + bool assigned = false; + if (_type != nulltype) { + ((_type == find_element_v ? + (*static_cast(_handle) = fennec::forward(t), assigned = true) : + (0) + ), ...); + } + + if (assigned) { + return *this; + } + + // Otherwise, destruct, then construct + _clear(); + using construct_t = search_element_args, TypesT...>; + fennec::construct(_handle, fennec::forward(t)); + return *this; + } + + template requires(contains_element_v) + void emplace(ArgsT&&...args) { + _clear(); + fennec::construct(_handle, fennec::forward(args)...); + } + + template + void emplace(ArgsT&&...args) { + using type_t = nth_element_t; + _clear(); + fennec::construct(fennec::forward(args)...); + } + + +// Access ============================================================================================================== + + template requires(contains_element_v) + T& get() { + return *static_cast(_handle); + } + + template requires(contains_element_v) + const T& get() const { + return *static_cast(_handle); + } + + template> requires(contains_element_v) + T& get() { + return *static_cast(_handle); + } + + template> requires(contains_element_v) + const T& get() const { + return *static_cast(_handle); + } + + + + +private: + union { + byte_t _bytes[size]; + void* _handle; + }; + size_t _type; + + void _clear() { + if (_type == nulltype) { + return; + } + + ((_type == find_element_v ? + fennec::destruct(_handle) : + (0) + ), ...); + _type = nulltype; + } +}; + +} + #endif // FENNEC_CONTAINERS_VARIANT_H \ No newline at end of file diff --git a/include/fennec/lang/detail/_type_sequences.h b/include/fennec/lang/detail/_type_sequences.h index 614cc03..3c0afe7 100644 --- a/include/fennec/lang/detail/_type_sequences.h +++ b/include/fennec/lang/detail/_type_sequences.h @@ -19,13 +19,19 @@ #ifndef FENNEC_LANG_DETAIL_TYPE_SEQUENCES_H #define FENNEC_LANG_DETAIL_TYPE_SEQUENCES_H +#include #include namespace fennec::detail { + template struct _type_sequence {}; template struct _first_element : type_identity {}; + + +// fennec::nth_element ================================================================================================= + template struct _nth_element; template struct _nth_element : type_identity {}; @@ -35,6 +41,56 @@ namespace fennec::detail n == i, HeadT, typename _nth_element::type > {}; + + + +// fennec::max_element_size ============================================================================================ + + template struct _max_element_size; + + template + struct _max_element_size + : integral_constant { + }; + + template + struct _max_element_size + : _max_element_size { + }; + + + +// fennec::find_element ================================================================================================ + + template struct _find_element; + + template + struct _find_element : integral_constant ? N : N + 1> {}; + + template requires(is_same_v) + struct _find_element + : conditional_t, integral_constant, _find_element> {}; + + +// fennec::search_element ============================================================================================== + + template typename, typename...> struct _search_element; + + template typename SearchT> struct _search_element : type_identity {}; + + template typename SearchT, typename HeadT, typename...RestT> requires(SearchT{}) + struct _search_element + : conditional_t{}, type_identity, _search_element> { + }; + + template typename, typename, typename...> struct _search_element_args; + + template typename SearchT, typename...ArgsT> + struct _search_element_args> : type_identity {}; + + template typename SearchT, typename HeadT, typename...RestT, typename...ArgsT> + struct _search_element_args, HeadT, RestT...> + : conditional_t{}, type_identity, _search_element_args, RestT...>> {}; } #endif // FENNEC_LANG_DETAIL_TYPE_SEQUENCES_H diff --git a/include/fennec/lang/detail/_type_traits.h b/include/fennec/lang/detail/_type_traits.h index c56e442..183b7b2 100644 --- a/include/fennec/lang/detail/_type_traits.h +++ b/include/fennec/lang/detail/_type_traits.h @@ -63,9 +63,19 @@ namespace fennec::detail template<> struct _is_floating_point : true_type {}; template<> struct _is_floating_point : true_type {}; - template struct _is_pointer : false_type {}; + template struct _is_pointer : false_type {}; template struct _is_pointer : true_type {}; + template struct _is_reference : false_type {}; + template struct _is_reference : true_type {}; + template struct _is_reference : true_type {}; + + template struct _is_lvalue_reference : false_type {}; + template struct _is_lvalue_reference : true_type {}; + + template struct _is_rvalue_reference : false_type {}; + template struct _is_rvalue_reference : true_type {}; + template struct _is_complete { template static auto test(U*) -> bool_constant; diff --git a/include/fennec/lang/intrinsics.h b/include/fennec/lang/intrinsics.h index 9e05bde..90172c5 100644 --- a/include/fennec/lang/intrinsics.h +++ b/include/fennec/lang/intrinsics.h @@ -213,6 +213,14 @@ # define FENNEC_HAS_BUILTIN_IS_ENUM 0 #endif +// Inconsistent without intrinsics. +#if __has_builtin(__is_union) +# define FENNEC_HAS_BUILTIN_IS_UNION 1 +# define FENNEC_BUILTIN_IS_UNION(arg) __is_union(arg) +#else +# define FENNEC_HAS_BUILTIN_IS_UNION 0 +#endif + // Inconsistent without intrinsics #if __has_builtin(__is_final) # define FENNEC_HAS_BUILTIN_IS_FINAL 1 @@ -221,12 +229,20 @@ # define FENNEC_HAS_BUILTIN_IS_FINAL 0 #endif -// Inconsistent with dynamic intrinsics, requires a massive table for static intrinsics -#if __has_builtin(__is_fundamental) -# define FENNEC_HAS_BUILTIN_IS_FUNDAMENTAL 1 -# define FENNEC_BUILTIN_IS_FUNDAMENTAL(arg) __is_fundamental(arg) +// Inconsistent without intrinsics +#if __has_builtin(__is_function) +# define FENNEC_HAS_BUILTIN_IS_FUNCTION 1 +# define FENNEC_BUILTIN_IS_FUNCTION(arg) __is_function(arg) #else -# define FENNEC_HAS_BUILTIN_IS_FUNDAMENTAL 0 +# define FENNEC_HAS_BUILTIN_IS_FUNCTION 0 +#endif + +// Inconsistent without intrinsics +#if __has_builtin(__is_object) +# define FENNEC_HAS_BUILTIN_IS_OBJECT 1 +# define FENNEC_BUILTIN_IS_OBJECT(arg) __is_object(arg) +#else +# define FENNEC_HAS_BUILTIN_IS_FUNCTION 0 #endif // Inconsistent without intrinsics diff --git a/include/fennec/lang/metaprogramming.h b/include/fennec/lang/metaprogramming.h index 82890a1..9e4c436 100644 --- a/include/fennec/lang/metaprogramming.h +++ b/include/fennec/lang/metaprogramming.h @@ -43,6 +43,7 @@ /// - \subpage fennec_lang_conditional_types /// - \subpage fennec_lang_numeric_transforms /// - \subpage fennec_lang_metasequences +/// - \subpage fennec_lang_type_identity /// - \subpage fennec_lang_type_sequences /// - \subpage fennec_lang_type_traits /// - \subpage fennec_lang_type_transforms diff --git a/include/fennec/lang/type_sequences.h b/include/fennec/lang/type_sequences.h index 22ed6dc..a8c6c78 100644 --- a/include/fennec/lang/type_sequences.h +++ b/include/fennec/lang/type_sequences.h @@ -51,6 +51,12 @@ /// \ref fennec::replace_first_element "typename replace_first_element::type"
/// /// \copydoc fennec::replace_first_element +/// +///
+/// \ref fennec::is_unique "is_unique::value"
+/// \ref fennec::is_unique_v "is_unique_v" +/// +/// \copydoc fennec::is_unique /// /// @@ -59,6 +65,12 @@ namespace fennec { + +template struct type_sequence {}; + + +// fennec::first_element =============================================================================================== + /// /// \brief Get the first element of a template parameter pack /// \tparam TypesT the Parameter Pack @@ -69,8 +81,20 @@ template struct first_element : detail::_first_element using first_element_t = typename first_element::type; + +// fennec::nth_element ================================================================================================= + +/// +/// \brief Gets the type of the nth element of the type sequence `TypesT...` +/// \tparam n The index in the type sequence +/// \tparam TypesT The type sequence template struct nth_element : detail::_nth_element {}; +template using nth_element_t = nth_element::type; + + + +// fennec::replace_first_element ======================================================================================= /// /// \brief Take a Template with a Pack `ClassT` and replace the first `ArgT` of `ArgsT...` with `SubT` @@ -84,6 +108,99 @@ template< struct replace_first_element, SubT> // Specialization { using type = ClassT; }; // Definition + + +// fennec::max_element_size ============================================================================================ + +/// +/// \brief Gets the max value of the size of each type in the sequence, i.e. `max(sizeof(Ts)...)` +/// \tparam Ts The type sequence to check +template struct max_element_size : detail::_max_element_size<0, Ts...> {}; + +/// +/// \brief Shorthand for `max_element_size::value` +/// \tparam Ts The type sequence to check +template constexpr size_t max_element_size_v = max_element_size::value; + + + +// fennec::find_element ================================================================================================ + +/// +/// \brief Finds the index of `T` in `Ts`, if `T` is not found, results in `sizeof...(Ts)` +/// \tparam T The type to find +/// \tparam Ts The type sequence to check +template struct find_element : detail::_find_element<0, T, Ts...> {}; + +/// +/// \brief Shorthand for `find_element::value` +/// \tparam T The type to find +/// \tparam Ts The type sequence to check +template constexpr size_t find_element_v = find_element::value; + + + +// fennec::search_element ============================================================================================== + + +/// +/// \brief Find the first element in `TypesT...` that satisfies `SearchT` +/// \tparam SearchT A type that satisfies `template` and contains `static constexpr bool value;` to use for searching +/// \tparam TypesT The type sequence to search +template typename SearchT, typename...TypesT> struct search_element : detail::_search_element {}; + +/// +/// \brief Shorthand for `search_element_t::type` +/// \tparam SearchT A type that satisfies `template` and contains `static constexpr bool value;` to use for searching +/// \tparam TypesT The type sequence to search +template typename SearchT, typename...TypesT> using search_element_t = search_element::type; + + +template typename, typename, typename...> struct search_element_args; + +template typename SearchT, typename...TypesT, typename...ArgsT> +struct search_element_args, TypesT...> + : detail::_search_element_args, TypesT...> { +}; + + + + +// fennec::contains_element ============================================================================================ + +/// +/// \brief Checks if the type sequence `Ts...` contains `T` +/// \tparam T The type to find +/// \tparam Ts The type sequence to check +template struct contains_element : bool_constant<(is_same_v or ...)> {}; + +/// +/// \brief Shorthand for `contains_element_v::value` +/// \tparam T The type to find +/// \tparam Ts The type sequence to check +template constexpr bool contains_element_v = contains_element::value; + + + +// fennec::is_unique =================================================================================================== + +/// +/// \brief Checks if all types in a type sequence are unique +/// \tparam Ts The type sequence to check +template struct is_unique : false_type {}; + +// Single type case +template struct is_unique : true_type {}; + +// Recursion case +template requires(not is_same_v && ...) +struct is_unique : is_unique {}; + +/// +/// \brief Shorthand for `is_unique::value` +/// \tparam Ts The type sequence to check +template constexpr bool is_unique_v = is_unique::value; + } diff --git a/include/fennec/lang/type_traits.h b/include/fennec/lang/type_traits.h index aee6efa..d56703f 100644 --- a/include/fennec/lang/type_traits.h +++ b/include/fennec/lang/type_traits.h @@ -360,7 +360,7 @@ /// \ref fennec::is_nothrow_move_constructible "is_nothrow_move_constructible::value"
/// \ref fennec::is_nothrow_move_constructible_v "is_nothrow_move_constructible_v" /// -/// \movedetails fennec::is_move_constructible +/// \copydetails fennec::is_move_constructible /// ///
/// \ref fennec::is_assignable "is_assignable::value"
@@ -390,7 +390,7 @@ /// \ref fennec::is_nothrow_move_assignable "is_nothrow_move_assignable::value"
/// \ref fennec::is_nothrow_move_assignable_v "is_nothrow_move_assignable_v" /// -/// \movedetails fennec::is_move_assignable +/// \copydetails fennec::is_move_assignable /// ///
/// \ref fennec::is_destructible "is_destructible::value"
@@ -446,7 +446,7 @@ constexpr inline bool is_constant_evaluated() noexcept { // fennec::is_void ===================================================================================================== /// -/// \brief check if \p T is of type void +/// \brief Check if \p T is of type void /// /// \details Stores a boolean value in `is_void::value`, representing whether the provided type is of base type void. /// \tparam T type to check @@ -454,7 +454,7 @@ template struct is_void : detail::_is_void>{}; /// -/// \brief shorthand for ```is_void::value``` +/// \brief Shorthand for ```is_void::value``` /// \tparam T type to check template constexpr bool_t is_void_v = is_void::value; @@ -463,7 +463,7 @@ template constexpr bool_t is_void_v = is_void::value; // fennec::is_null_pointer ============================================================================================= /// -/// \brief check if \p T is of type nullptr_t +/// \brief Check if \p T is of type nullptr_t /// /// \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 @@ -471,7 +471,7 @@ template struct is_null_pointer : detail::_is_null_pointer>{}; /// -/// \brief shorthand for ```is_null_pointer::value``` +/// \brief Shorthand for ```is_null_pointer::value``` /// \tparam T type to check template constexpr bool_t is_null_pointer_v = is_null_pointer::value; @@ -482,7 +482,7 @@ template constexpr bool_t is_null_pointer_v = is_null_pointer::va #ifdef FENNEC_BUILTIN_IS_ARRAY /// -/// \brief check if \p T is of an array type +/// \brief Check if \p T is of an array type /// \tparam T type to check template struct is_array : bool_constant {}; @@ -490,7 +490,7 @@ template struct is_array #else /// -/// \brief check if \p T is of an array type +/// \brief Check if \p T is of an array type /// \tparam T type to check template struct is_array : false_type {}; @@ -506,25 +506,72 @@ template struct is_array #endif /// -/// \brief shorthand for ```is_array::value``` +/// \brief Shorthand for ```is_array::value``` /// \tparam T type to check template constexpr bool_t is_array_v = is_array::value; + + +// fennec::is_enum ==================================================================================================== + +/// +/// \brief Check if \p T is an enum +/// \tparam T type to check +template struct is_enum + : bool_constant {}; + +/// +/// \brief Check if \p T is a class +/// \tparam T type to check +template constexpr size_t is_enum_v = is_enum::value; + + + +// fennec::is_union ==================================================================================================== + +/// +/// \brief Check if \p T is a union +/// \tparam T type to check +template struct is_union + : bool_constant {}; + +/// +/// \brief Check if \p T is a class +/// \tparam T type to check +template constexpr size_t is_union_v = is_union::value; + + + // fennec::is_class ==================================================================================================== /// -/// \brief check if \p T is a class +/// \brief Check if \p T is a class /// \tparam T type to check template struct is_class : bool_constant {}; /// -/// \brief check if \p T is a class +/// \brief Check if \p T is a class /// \tparam T type to check template constexpr size_t is_class_v = is_class::value; +// fennec::is_function ==================================================================================================== + +/// +/// \brief Check if \p T is a class +/// \tparam T type to check +template struct is_function + : bool_constant {}; + +/// +/// \brief Check if \p T is a class +/// \tparam T type to check +template constexpr size_t is_function_v = is_function::value; + + + // Integral Types ====================================================================================================== @@ -532,7 +579,7 @@ template constexpr size_t is_class_v = is_class::value; // fennec::is_bool ===================================================================================================== /// -/// \brief check if \p T is of type 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 @@ -540,12 +587,16 @@ template struct is_bool : detail::_is_bool>{}; /// -/// \brief shorthand for ```is_bool::value``` +/// \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 +/// \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 @@ -553,13 +604,17 @@ template struct is_integral : detail::_is_integral> {}; /// -/// \brief shorthand for ```is_integral::value``` +/// \brief Shorthand for ```is_integral::value``` /// \tparam T type to check template constexpr bool_t is_integral_v = is_integral::value; + +// fennec::is_signed ================================================================================================= + + /// -/// \brief check if \p T is of a signed integral +/// \brief Check if \p T is of a signed integral /// /// \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 @@ -567,13 +622,17 @@ template struct is_signed : detail::_is_signed> {}; /// -/// \brief shorthand for ```is_signed::value``` +/// \brief Shorthand for ```is_signed::value``` /// \tparam T type to check template constexpr bool_t is_signed_v = is_signed::value; + +// fennec::is_unsigned ================================================================================================= + + /// -/// \brief check if \p T is of an unsigned integral +/// \brief Check if \p T is of an unsigned integral /// /// \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 @@ -581,7 +640,7 @@ template struct is_unsigned : detail::_is_unsigned> {}; /// -/// \brief shorthand for ```is_unsigned::value``` +/// \brief Shorthand for ```is_unsigned::value``` /// \tparam T type to check template constexpr bool_t is_unsigned_v = is_unsigned::value; @@ -590,15 +649,15 @@ template constexpr bool_t is_unsigned_v = is_unsigned::value; // Floating Point Types ================================================================================================ /// -/// \brief check if \p T is of a floating point type +/// \brief Check if \p T is of a floating point type /// -/// \details Checks if type `T` is a floating point type and store it in `is_same::value`. +/// \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``` +/// \brief Shorthand for ```is_floating_point::value``` /// \tparam T type to check template constexpr bool_t is_floating_point_v = is_floating_point {}; @@ -606,24 +665,69 @@ template constexpr bool_t is_floating_point_v = is_floating_point // Pointer Types ======================================================================================================= /// -/// \brief check if \p T is of a floating point type +/// \brief Check if \p T is of a pointer type /// -/// \details Checks if type `T` is a floating point type and store it in `is_same::value`. +/// \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_floating_point::value``` +/// \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 +/// \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 @@ -631,21 +735,38 @@ template struct is_arithmetic : bool_constant or is_floating_point_v>{}; /// -/// \brief shorthand for ```is_arithmetic::value``` +/// \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 +/// \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``` +/// \brief Shorthand for ```is_fundamental::value``` /// \tparam T type to check template constexpr bool_t is_fundamental_v = is_fundamental::value; @@ -653,7 +774,7 @@ template constexpr bool_t is_fundamental_v = is_fundamental::valu // fennec::is_same ===================================================================================================== /// -/// \brief check if the two types are identical +/// \brief Check if the two types are identical /// /// \details Checks if `T0` and `T1` are identical and store it in `is_same::value` /// \tparam T0 first type to check @@ -664,7 +785,7 @@ template struct is_same : false_type {}; template struct is_same : true_type {}; /// -/// \brief shorthand for ```is_same::value``` +/// \brief Shorthand for ```is_same::value``` /// \tparam T0 first type to check /// \tparam T1 second type to check template constexpr bool_t is_same_v = is_same {}; @@ -672,63 +793,63 @@ template constexpr bool_t is_same_v = is_same // fennec::is_complete ============================================================================================== /// -/// \brief check if type `T` 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` +/// \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 +/// \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` +/// \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 +/// \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` +/// \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 +/// \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` +/// \brief Shorthand for `is_mappable::value` /// \tparam T type to check template constexpr bool_t is_mappable_v = is_mappable{}; // fennec::is_convertible ============================================================================================== /// -/// \brief check if type `T0` can be converted `T1` +/// \brief Check if type `T0` can be converted `T1` /// /// \details Checks if `TypeT0` /// \tparam FromT First type @@ -737,7 +858,7 @@ template struct is_convertible : bool_constant {}; /// -/// \brief shorthand for `can_convert::value` +/// \brief Shorthand for `can_convert::value` /// \param FromT First type /// \param ToT Second type template constexpr bool_t is_convertible_v = is_convertible{}; @@ -779,7 +900,7 @@ template struct is_default_constructible /// /// \brief Shorthand for `is_default_constructible::value` -template constexpr bool_t is_default_constructible_v = is_default_constructible{}; +template constexpr bool_t is_default_constructible_v = is_default_constructible{}; diff --git a/include/fennec/lang/types.h b/include/fennec/lang/types.h index 061ab62..c3874ca 100644 --- a/include/fennec/lang/types.h +++ b/include/fennec/lang/types.h @@ -213,6 +213,8 @@ namespace fennec using bool_t = bool; ///< \brief A conditional type + using byte_t = unsigned char; ///< \brief A type capable of holding a single byte + using char_t = char; ///< \brief A type capable of holding an ascii value using schar_t = signed char; ///< \brief A type with the size of a char, capable of holding a signed 8-bit integer using uchar_t = unsigned char; ///< \brief A type with the size of a char, capable of holding an unsigned 8-bit integer diff --git a/include/fennec/platform/interface/platform.h b/include/fennec/platform/interface/platform.h index 9ad9580..833637c 100644 --- a/include/fennec/platform/interface/platform.h +++ b/include/fennec/platform/interface/platform.h @@ -26,6 +26,7 @@ #include #include #include +#include #include /* @@ -62,12 +63,12 @@ namespace fennec { -class platform { +class platform : singleton { public: using shared_object = struct shared_object; using symbol = void*; - platform() = default; + platform(); virtual ~platform() = default; platform(const platform&) = delete; diff --git a/include/fennec/platform/linux/platform.h b/include/fennec/platform/linux/platform.h index 7aad820..fe70552 100644 --- a/include/fennec/platform/linux/platform.h +++ b/include/fennec/platform/linux/platform.h @@ -32,6 +32,9 @@ public: void initialize() override; void shutdown() override; + + FENNEC_RTTI_CLASS_ENABLE(unix_platform) { + } }; } diff --git a/include/fennec/platform/unix/platform.h b/include/fennec/platform/unix/platform.h index 6e56892..c8411f9 100644 --- a/include/fennec/platform/unix/platform.h +++ b/include/fennec/platform/unix/platform.h @@ -35,7 +35,9 @@ public: symbol find_symbol(shared_object* obj, const cstring& name) override; private: + FENNEC_RTTI_CLASS_ENABLE(platform) { + } }; } diff --git a/include/fennec/rtti/enable.h b/include/fennec/rtti/enable.h index 503f594..8d4ce8d 100644 --- a/include/fennec/rtti/enable.h +++ b/include/fennec/rtti/enable.h @@ -41,7 +41,7 @@ #define FENNEC_RTTI_CLASS_ENABLE(...) \ public: \ using super_class_list = fennec::typelist<__VA_ARGS__>; \ - virtual fennec::type get_type() { return fennec::type::get_from_instance(this); } \ + virtual inline fennec::type get_type() const { return fennec::type::get_from_instance(this); } \ FENNEC_DEFINE_THIS_T; \ private: \ FENNEC_CLASS_STATIC_CONSTRUCTOR(_init_reflection) diff --git a/include/fennec/rtti/forward.h b/include/fennec/rtti/forward.h index 35620fa..4ec1fc4 100644 --- a/include/fennec/rtti/forward.h +++ b/include/fennec/rtti/forward.h @@ -31,4 +31,17 @@ #ifndef FENNEC_RTTI_FORWARD_H #define FENNEC_RTTI_FORWARD_H +namespace fennec +{ + +class function; +struct vtypelist; +template struct typelist; + +struct type; +struct type_data; +struct type_storage; + +} + #endif // FENNEC_RTTI_FORWARD_H \ No newline at end of file diff --git a/include/fennec/rtti/singleton.h b/include/fennec/rtti/singleton.h new file mode 100644 index 0000000..fb39e5b --- /dev/null +++ b/include/fennec/rtti/singleton.h @@ -0,0 +1,52 @@ +// ===================================================================================================================== +// 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 singleton.h +/// \brief +/// +/// +/// \details +/// \author Medusa Slockbower +/// +/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html)) +/// +/// + +#ifndef FENNEC_RTTI_SINGLETON_H +#define FENNEC_RTTI_SINGLETON_H + +namespace fennec +{ + +template +struct singleton { + static T& instance() requires(is_pointer_v) { + static T instance = nullptr; + return instance; + } + + static T& instance() requires(is_default_constructible_v and not is_pointer_v) { + static T instance; + return instance; + } +}; + +} + +#endif // FENNEC_RTTI_SINGLETON_H \ No newline at end of file diff --git a/include/fennec/rtti/type_data.h b/include/fennec/rtti/type_data.h index 1988a48..adfdb42 100644 --- a/include/fennec/rtti/type_data.h +++ b/include/fennec/rtti/type_data.h @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include namespace fennec diff --git a/include/fennec/rtti/type_registry.h b/include/fennec/rtti/type_registry.h new file mode 100644 index 0000000..e4a9010 --- /dev/null +++ b/include/fennec/rtti/type_registry.h @@ -0,0 +1,85 @@ +// ===================================================================================================================== +// 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 type_registry.h +/// \brief +/// +/// +/// \details +/// \author Medusa Slockbower +/// +/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html)) +/// +/// + +#ifndef FENNEC_RTTI_TYPE_REGISTRY_H +#define FENNEC_RTTI_TYPE_REGISTRY_H +#include +#include + +namespace fennec +{ + +template +class type_registry { +public: + using ctor_t = BaseT (*)(ArgsT&&...); + + struct entry { + size_t priority; + type type; + ctor_t ctor; + }; + + struct compare { + bool operator()(const entry& a, const entry& b) const { + return a.priority > b.priority and a.ctor < b.ctor; + } + }; + + using entrylist_t = priority_queue; + + template + static void register_type(size_t priority = 0) { + _global_list().emplace( + priority, + type::get(), + _constructor_helper + ); + } + + static const entrylist_t& get_type_list() { + return _global_list(); + } + +private: + static entrylist_t& _global_list() { + static entrylist_t list; + return list; + } + + template + static BaseT* _constructor_helper(ArgsT&&...args) { + return new T(fennec::forward(args)...); + } +}; + +} + +#endif // FENNEC_RTTI_TYPE_REGISTRY_H \ No newline at end of file diff --git a/include/fennec/rtti/typelist.h b/include/fennec/rtti/typelist.h index 5e66b93..748af7e 100644 --- a/include/fennec/rtti/typelist.h +++ b/include/fennec/rtti/typelist.h @@ -32,13 +32,23 @@ #define FENNEC_RTTI_TYPELIST_H #include +#include namespace fennec { +struct vtypelist { + virtual ~vtypelist() = default; + virtual dynarray get() = 0; +}; + template -struct typelist { +struct typelist : vtypelist { static constexpr size_t size = sizeof...(TypesT); + + virtual dynarray get() { + return { type::get()... }; + } }; } diff --git a/planning/CONTAINERS.md b/planning/CONTAINERS.md index 424d808..dabe4eb 100644 --- a/planning/CONTAINERS.md +++ b/planning/CONTAINERS.md @@ -40,7 +40,7 @@ Library and Template Library. | tuple | 🚧 | 🚧 | | optional | ✅ | ✅ | | variant | ⛔ | ⛔ | -| any | ⛔ | ⛔ | +| generic (`std::any`) | ⛔ | ⛔ | | bitset | ⛔ | ⛔ | | array | ✅ | ✅ | | dynarray (`std::vector`) | 🚧 | 🚧 | diff --git a/planning/CPP_LANGUAGE.md b/planning/CPP_LANGUAGE.md index 8e8a092..cc34891 100644 --- a/planning/CPP_LANGUAGE.md +++ b/planning/CPP_LANGUAGE.md @@ -61,7 +61,7 @@ See: | is_null_pointer | ✅ | ✅ | | is_integral | ✅ | ✅ | | is_floating_point | ✅ | ✅ | -| is_array | ✅ | 🚧 | +| is_array | ✅ | 🚧 | | is_enum | ⛔ | ⛔ | | is_union | ⛔ | ⛔ | | is_class | ✅ | ✅ | diff --git a/source/platform/interface/platform.cpp b/source/platform/interface/platform.cpp index d070600..7741fa1 100644 --- a/source/platform/interface/platform.cpp +++ b/source/platform/interface/platform.cpp @@ -21,6 +21,11 @@ namespace fennec { +platform::platform() { + assertf(instance() == nullptr, "Attempted to instantiate multiple platforms."); + instance() = this; +} + void platform::initialize() { }