- fennec::variant & fennec::generic, TODO: Test
This commit is contained in:
210
include/fennec/containers/generic.h
Normal file
210
include/fennec/containers/generic.h
Normal file
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
///
|
||||
/// \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 <fennec/memory/allocator.h>
|
||||
#include <fennec/rtti/type.h>
|
||||
|
||||
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<typename T>
|
||||
generic(T&& x)
|
||||
: _handle(new T(fennec::forward<T>(x)))
|
||||
, _manage(_manage_impl<T>) {
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Emplace Constructor
|
||||
/// \tparam T The type to construct
|
||||
/// \tparam ArgsT The argument types
|
||||
/// \param args The argument values
|
||||
template<typename T, typename...ArgsT>
|
||||
generic(type_identity<T>, ArgsT&&...args)
|
||||
: _handle(new T(fennec::forward<ArgsT>(args)...))
|
||||
, _manage(_manage_impl<T>) {
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Destructor
|
||||
~generic() {
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
// Properties ==========================================================================================================
|
||||
|
||||
type type() const {
|
||||
return *static_cast<fennec::type*>(_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<typename T>
|
||||
generic& operator=(T&& x) {
|
||||
reset();
|
||||
_handle = new T(fennec::forward<T>(x));
|
||||
_manage = _manage_impl<T>();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T, typename...ArgsT>
|
||||
void emplace(ArgsT&&...args) {
|
||||
reset();
|
||||
_handle = new T(fennec::forward<ArgsT>(args)...);
|
||||
_manage = _manage_impl<T>;
|
||||
}
|
||||
|
||||
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<typename T>
|
||||
T& cast() {
|
||||
return *static_cast<T*>(_handle);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T& cast() const {
|
||||
return *static_cast<T*>(_handle);
|
||||
}
|
||||
|
||||
private:
|
||||
void* _handle;
|
||||
manager_t _manage;
|
||||
|
||||
template<typename T>
|
||||
static void* _manage_impl(uint8_t op, void* hnd) {
|
||||
static fennec::type t = type::get<T>();
|
||||
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
|
||||
@@ -31,4 +31,216 @@
|
||||
#ifndef FENNEC_CONTAINERS_VARIANT_H
|
||||
#define FENNEC_CONTAINERS_VARIANT_H
|
||||
|
||||
#include <fennec/containers/optional.h>
|
||||
#include <fennec/lang/type_sequences.h>
|
||||
#include <fennec/math/ext/common.h>
|
||||
#include <fennec/rtti/type.h>
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
///
|
||||
/// \brief A structure that represents a union between `TypesT...`
|
||||
/// \tparam TypesT The types to hold in the variant
|
||||
template<typename...TypesT>
|
||||
struct variant {
|
||||
// Assertions ==========================================================================================================
|
||||
|
||||
static_assert(
|
||||
is_unique_v<TypesT...> and // No two types in TypesT... may be equivalent
|
||||
not (is_reference_v<TypesT> or ...) and // No type in TypesT... may be a reference
|
||||
not (is_array_v<TypesT> or ...) and // No type in TypesT... may be an array
|
||||
not (is_void_v<TypesT> or ...) // No type in TypesT... may be void
|
||||
);
|
||||
|
||||
|
||||
// Typedefs & Constants ================================================================================================
|
||||
|
||||
static constexpr size_t size = max_element_size_v<TypesT...>;
|
||||
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<is_default_constructible, TypesT...>;
|
||||
fennec::construct<construct_t>(_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<typename T>
|
||||
variant(T&& t)
|
||||
: _bytes {}
|
||||
, _type() {
|
||||
using same_t = search_element_args<is_same, type_sequence<T>, TypesT...>;
|
||||
using convert_t = search_element_args<is_constructible, type_sequence<T>, TypesT...>;
|
||||
using construct_t = conditional_t<is_void_v<same_t>, convert_t, convert_t>;
|
||||
fennec::construct<construct_t>(_handle, fennec::forward<T>(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<typename T, typename...ArgsT>
|
||||
variant(type_identity<T>, ArgsT&&...args)
|
||||
: _bytes{}
|
||||
, _type(nulltype) {
|
||||
static_assert(contains_element_v<T, TypesT...>, "T must be in TypesT...");
|
||||
fennec::construct<T>(_handle, fennec::forward<ArgsT>(args)...);
|
||||
_type = find_element_v<T>;
|
||||
}
|
||||
|
||||
///
|
||||
/// \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<TypesT, TypesT...> ?
|
||||
fennec::construct<TypesT>(_handle, v.get<TypesT>()) :
|
||||
(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<TypesT, TypesT...> ?
|
||||
fennec::construct<TypesT>(_handle, fennec::move(v.get<TypesT>())) :
|
||||
(0)
|
||||
), ...);
|
||||
_type = v._type;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Destructor, if a type is held, destruct it.
|
||||
~variant() {
|
||||
_clear();
|
||||
}
|
||||
|
||||
|
||||
// Assignment ==========================================================================================================
|
||||
|
||||
template<typename T>
|
||||
variant& operator=(T&& t) {
|
||||
|
||||
// First, check if `T` is in `TypesT...`
|
||||
if constexpr((contains_element_v<T, TypesT> or ...)) {
|
||||
using type_t = remove_reference_t<T>;
|
||||
if (_type == find_element_v<type_t, TypesT...>) {
|
||||
*static_cast<type_t*>(_handle) = fennec::forward<T>(t);
|
||||
} else {
|
||||
_clear();
|
||||
fennec::construct<type_t>(_handle, fennec::forward<T>(t));
|
||||
_type = find_element_v<type_t, TypesT...>;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Next, try to assign using the currently held type
|
||||
bool assigned = false;
|
||||
if (_type != nulltype) {
|
||||
((_type == find_element_v<TypesT, TypesT...> ?
|
||||
(*static_cast<TypesT*>(_handle) = fennec::forward<T>(t), assigned = true) :
|
||||
(0)
|
||||
), ...);
|
||||
}
|
||||
|
||||
if (assigned) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Otherwise, destruct, then construct
|
||||
_clear();
|
||||
using construct_t = search_element_args<is_constructible, type_sequence<T>, TypesT...>;
|
||||
fennec::construct<construct_t>(_handle, fennec::forward<T>(t));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T, typename...ArgsT> requires(contains_element_v<T, TypesT...>)
|
||||
void emplace(ArgsT&&...args) {
|
||||
_clear();
|
||||
fennec::construct<T>(_handle, fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
|
||||
template<size_t I, typename...ArgsT>
|
||||
void emplace(ArgsT&&...args) {
|
||||
using type_t = nth_element_t<I, TypesT...>;
|
||||
_clear();
|
||||
fennec::construct<type_t>(fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
|
||||
|
||||
// Access ==============================================================================================================
|
||||
|
||||
template<typename T> requires(contains_element_v<T, TypesT...>)
|
||||
T& get() {
|
||||
return *static_cast<T*>(_handle);
|
||||
}
|
||||
|
||||
template<typename T> requires(contains_element_v<T, TypesT...>)
|
||||
const T& get() const {
|
||||
return *static_cast<T*>(_handle);
|
||||
}
|
||||
|
||||
template<size_t I, typename T = nth_element_t<I, TypesT...>> requires(contains_element_v<T, TypesT...>)
|
||||
T& get() {
|
||||
return *static_cast<T*>(_handle);
|
||||
}
|
||||
|
||||
template<size_t I, typename T = nth_element_t<I, TypesT...>> requires(contains_element_v<T, TypesT...>)
|
||||
const T& get() const {
|
||||
return *static_cast<T*>(_handle);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private:
|
||||
union {
|
||||
byte_t _bytes[size];
|
||||
void* _handle;
|
||||
};
|
||||
size_t _type;
|
||||
|
||||
void _clear() {
|
||||
if (_type == nulltype) {
|
||||
return;
|
||||
}
|
||||
|
||||
((_type == find_element_v<TypesT, TypesT...> ?
|
||||
fennec::destruct<TypesT>(_handle) :
|
||||
(0)
|
||||
), ...);
|
||||
_type = nulltype;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FENNEC_CONTAINERS_VARIANT_H
|
||||
@@ -19,13 +19,19 @@
|
||||
#ifndef FENNEC_LANG_DETAIL_TYPE_SEQUENCES_H
|
||||
#define FENNEC_LANG_DETAIL_TYPE_SEQUENCES_H
|
||||
|
||||
#include <fennec/math/common.h>
|
||||
#include <fennec/lang/type_transforms.h>
|
||||
|
||||
namespace fennec::detail
|
||||
{
|
||||
template<typename...TypesT> struct _type_sequence {};
|
||||
|
||||
template<typename FirstT, typename... RestT> struct _first_element : type_identity<FirstT> {};
|
||||
|
||||
|
||||
|
||||
// fennec::nth_element =================================================================================================
|
||||
|
||||
template<size_t n, size_t i, typename...TypesT> struct _nth_element;
|
||||
|
||||
template<size_t n, size_t i> struct _nth_element<n, i> : type_identity<void> {};
|
||||
@@ -35,6 +41,56 @@ namespace fennec::detail
|
||||
n == i, HeadT,
|
||||
typename _nth_element<n, i + 1, RestT...>::type
|
||||
> {};
|
||||
|
||||
|
||||
|
||||
// fennec::max_element_size ============================================================================================
|
||||
|
||||
template<size_t, typename...> struct _max_element_size;
|
||||
|
||||
template<size_t M, typename HeadT>
|
||||
struct _max_element_size<M, HeadT>
|
||||
: integral_constant<size_t, fennec::max(M, sizeof(HeadT))> {
|
||||
};
|
||||
|
||||
template<size_t M, typename HeadT, typename...RestT>
|
||||
struct _max_element_size<M, HeadT, RestT...>
|
||||
: _max_element_size<fennec::max(M, sizeof(HeadT)), RestT...> {
|
||||
};
|
||||
|
||||
|
||||
|
||||
// fennec::find_element ================================================================================================
|
||||
|
||||
template<size_t N, typename, typename...> struct _find_element;
|
||||
|
||||
template<size_t N, typename FindT, typename HeadT>
|
||||
struct _find_element<N, FindT, HeadT> : integral_constant<size_t, is_same_v<FindT, HeadT> ? N : N + 1> {};
|
||||
|
||||
template<size_t N, typename FindT, typename HeadT, typename...RestT> requires(is_same_v<FindT, HeadT>)
|
||||
struct _find_element<N, FindT, HeadT, RestT...>
|
||||
: conditional_t<is_same_v<FindT, HeadT>, integral_constant<size_t, N>, _find_element<N + 1, FindT, RestT...>> {};
|
||||
|
||||
|
||||
// fennec::search_element ==============================================================================================
|
||||
|
||||
template<template<typename> typename, typename...> struct _search_element;
|
||||
|
||||
template<template<typename> typename SearchT> struct _search_element<SearchT> : type_identity<void> {};
|
||||
|
||||
template<template<typename> typename SearchT, typename HeadT, typename...RestT> requires(SearchT<HeadT>{})
|
||||
struct _search_element<SearchT, HeadT, RestT...>
|
||||
: conditional_t<SearchT<HeadT>{}, type_identity<HeadT>, _search_element<SearchT, RestT...>> {
|
||||
};
|
||||
|
||||
template<template<typename, typename...> typename, typename, typename...> struct _search_element_args;
|
||||
|
||||
template<template<typename, typename...> typename SearchT, typename...ArgsT>
|
||||
struct _search_element_args<SearchT, _type_sequence<ArgsT...>> : type_identity<void> {};
|
||||
|
||||
template<template<typename, typename...> typename SearchT, typename HeadT, typename...RestT, typename...ArgsT>
|
||||
struct _search_element_args<SearchT, _type_sequence<ArgsT...>, HeadT, RestT...>
|
||||
: conditional_t<SearchT<HeadT, ArgsT...>{}, type_identity<HeadT>, _search_element_args<SearchT, _type_sequence<ArgsT...>, RestT...>> {};
|
||||
}
|
||||
|
||||
#endif // FENNEC_LANG_DETAIL_TYPE_SEQUENCES_H
|
||||
|
||||
@@ -63,9 +63,19 @@ namespace fennec::detail
|
||||
template<> struct _is_floating_point<float_t> : true_type {};
|
||||
template<> struct _is_floating_point<double_t> : true_type {};
|
||||
|
||||
template<typename> struct _is_pointer : false_type {};
|
||||
template<typename> struct _is_pointer : false_type {};
|
||||
template<typename T> struct _is_pointer<T*> : true_type {};
|
||||
|
||||
template<typename> struct _is_reference : false_type {};
|
||||
template<typename T> struct _is_reference<T&> : true_type {};
|
||||
template<typename T> struct _is_reference<T&&> : true_type {};
|
||||
|
||||
template<typename> struct _is_lvalue_reference : false_type {};
|
||||
template<typename T> struct _is_lvalue_reference<T&> : true_type {};
|
||||
|
||||
template<typename> struct _is_rvalue_reference : false_type {};
|
||||
template<typename T> struct _is_rvalue_reference<T&&> : true_type {};
|
||||
|
||||
template<typename T> struct _is_complete {
|
||||
template<typename U>
|
||||
static auto test(U*) -> bool_constant<sizeof(U) == sizeof(U)>;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -51,6 +51,12 @@
|
||||
/// \ref fennec::replace_first_element "typename replace_first_element<ClassT, SubT, OriginT, RestT...>::type"<br>
|
||||
/// <td width="50%" style="vertical-align: top">
|
||||
/// \copydoc fennec::replace_first_element
|
||||
///
|
||||
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||
/// \ref fennec::is_unique "is_unique<TypesT...>::value"<br>
|
||||
/// \ref fennec::is_unique_v "is_unique_v<TypesT...>"
|
||||
/// <td width="50%" style="vertical-align: top">
|
||||
/// \copydoc fennec::is_unique
|
||||
/// </table>
|
||||
///
|
||||
|
||||
@@ -59,6 +65,12 @@
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
|
||||
template<typename...TypesT> 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<typename...TypesT> struct first_element : detail::_first_element<TypesT
|
||||
template<typename...TypesT> using first_element_t = typename first_element<TypesT...>::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<size_t n, typename...TypesT> struct nth_element : detail::_nth_element<n, 0, TypesT...> {};
|
||||
|
||||
template<size_t n, typename...TypesT> using nth_element_t = nth_element<n, TypesT...>::type;
|
||||
|
||||
|
||||
|
||||
// fennec::replace_first_element =======================================================================================
|
||||
|
||||
///
|
||||
/// \brief Take a Template with a Pack `ClassT<ArgsT...>` and replace the first `ArgT` of `ArgsT...` with `SubT`
|
||||
@@ -84,6 +108,99 @@ template<
|
||||
struct replace_first_element<ClassT<OriginT, RestT...>, SubT> // Specialization
|
||||
{ using type = ClassT<SubT, RestT...>; }; // 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<typename...Ts> struct max_element_size : detail::_max_element_size<0, Ts...> {};
|
||||
|
||||
///
|
||||
/// \brief Shorthand for `max_element_size<Ts...>::value`
|
||||
/// \tparam Ts The type sequence to check
|
||||
template<typename...Ts> constexpr size_t max_element_size_v = max_element_size<Ts...>::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<typename T, typename...Ts> struct find_element : detail::_find_element<0, T, Ts...> {};
|
||||
|
||||
///
|
||||
/// \brief Shorthand for `find_element<T, Ts...>::value`
|
||||
/// \tparam T The type to find
|
||||
/// \tparam Ts The type sequence to check
|
||||
template<typename T, typename...Ts> constexpr size_t find_element_v = find_element<T, Ts...>::value;
|
||||
|
||||
|
||||
|
||||
// fennec::search_element ==============================================================================================
|
||||
|
||||
|
||||
///
|
||||
/// \brief Find the first element in `TypesT...` that satisfies `SearchT<T>`
|
||||
/// \tparam SearchT A type that satisfies `template<typename>` and contains `static constexpr bool value;` to use for searching
|
||||
/// \tparam TypesT The type sequence to search
|
||||
template<template<typename> typename SearchT, typename...TypesT> struct search_element : detail::_search_element<SearchT, TypesT...> {};
|
||||
|
||||
///
|
||||
/// \brief Shorthand for `search_element_t<T, Ts...>::type`
|
||||
/// \tparam SearchT A type that satisfies `template<typename>` and contains `static constexpr bool value;` to use for searching
|
||||
/// \tparam TypesT The type sequence to search
|
||||
template<template<typename> typename SearchT, typename...TypesT> using search_element_t = search_element<SearchT, TypesT...>::type;
|
||||
|
||||
|
||||
template<template<typename, typename...> typename, typename, typename...> struct search_element_args;
|
||||
|
||||
template<template<typename, typename...> typename SearchT, typename...TypesT, typename...ArgsT>
|
||||
struct search_element_args<SearchT, type_sequence<ArgsT...>, TypesT...>
|
||||
: detail::_search_element_args<SearchT, detail::_type_sequence<ArgsT...>, 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<typename T, typename...Ts> struct contains_element : bool_constant<(is_same_v<T, Ts> or ...)> {};
|
||||
|
||||
///
|
||||
/// \brief Shorthand for `contains_element_v<T, Ts...>::value`
|
||||
/// \tparam T The type to find
|
||||
/// \tparam Ts The type sequence to check
|
||||
template<typename T, typename...Ts> constexpr bool contains_element_v = contains_element<T, Ts...>::value;
|
||||
|
||||
|
||||
|
||||
// fennec::is_unique ===================================================================================================
|
||||
|
||||
///
|
||||
/// \brief Checks if all types in a type sequence are unique
|
||||
/// \tparam Ts The type sequence to check
|
||||
template<typename...Ts> struct is_unique : false_type {};
|
||||
|
||||
// Single type case
|
||||
template<typename T> struct is_unique<T> : true_type {};
|
||||
|
||||
// Recursion case
|
||||
template<typename T, typename...Ts> requires(not is_same_v<T, Ts> && ...)
|
||||
struct is_unique<T, Ts...> : is_unique<Ts...> {};
|
||||
|
||||
///
|
||||
/// \brief Shorthand for `is_unique<Ts...>::value`
|
||||
/// \tparam Ts The type sequence to check
|
||||
template<typename...Ts> constexpr bool is_unique_v = is_unique<Ts...>::value;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -360,7 +360,7 @@
|
||||
/// \ref fennec::is_nothrow_move_constructible "is_nothrow_move_constructible<ClassT, ArgsT...>::value"<br>
|
||||
/// \ref fennec::is_nothrow_move_constructible_v "is_nothrow_move_constructible_v<ClassT, ArgsT...>"
|
||||
/// <td width="50%" style="vertical-align: top">
|
||||
/// \movedetails fennec::is_move_constructible
|
||||
/// \copydetails fennec::is_move_constructible
|
||||
///
|
||||
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||
/// \ref fennec::is_assignable "is_assignable<ClassT, ArgsT...>::value"<br>
|
||||
@@ -390,7 +390,7 @@
|
||||
/// \ref fennec::is_nothrow_move_assignable "is_nothrow_move_assignable<ClassT, ArgsT...>::value"<br>
|
||||
/// \ref fennec::is_nothrow_move_assignable_v "is_nothrow_move_assignable_v<ClassT, ArgsT...>"
|
||||
/// <td width="50%" style="vertical-align: top">
|
||||
/// \movedetails fennec::is_move_assignable
|
||||
/// \copydetails fennec::is_move_assignable
|
||||
///
|
||||
/// <tr><td width="50%" style="vertical-align: top"> <br>
|
||||
/// \ref fennec::is_destructible "is_destructible<ClassT, ArgsT...>::value"<br>
|
||||
@@ -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<typename T> struct is_void
|
||||
: detail::_is_void<remove_cvr_t<T>>{};
|
||||
|
||||
///
|
||||
/// \brief shorthand for ```is_void<T>::value```
|
||||
/// \brief Shorthand for ```is_void<T>::value```
|
||||
/// \tparam T type to check
|
||||
template<typename T> constexpr bool_t is_void_v = is_void<T>::value;
|
||||
|
||||
@@ -463,7 +463,7 @@ template<typename T> constexpr bool_t is_void_v = is_void<T>::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<typename T> struct is_null_pointer
|
||||
: detail::_is_null_pointer<remove_cvr_t<T>>{};
|
||||
|
||||
///
|
||||
/// \brief shorthand for ```is_null_pointer<T>::value```
|
||||
/// \brief Shorthand for ```is_null_pointer<T>::value```
|
||||
/// \tparam T type to check
|
||||
template<typename T> constexpr bool_t is_null_pointer_v = is_null_pointer<T>::value;
|
||||
|
||||
@@ -482,7 +482,7 @@ template<typename T> constexpr bool_t is_null_pointer_v = is_null_pointer<T>::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<typename T> struct is_array
|
||||
: bool_constant<FENNEC_BUILTIN_IS_ARRAY(T)> {};
|
||||
@@ -490,7 +490,7 @@ template<typename T> 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<typename T> struct is_array
|
||||
: false_type {};
|
||||
@@ -506,25 +506,72 @@ template<typename T> struct is_array<T[]>
|
||||
#endif
|
||||
|
||||
///
|
||||
/// \brief shorthand for ```is_array<T>::value```
|
||||
/// \brief Shorthand for ```is_array<T>::value```
|
||||
/// \tparam T type to check
|
||||
template<typename T> constexpr bool_t is_array_v = is_array<T>::value;
|
||||
|
||||
|
||||
|
||||
// fennec::is_enum ====================================================================================================
|
||||
|
||||
///
|
||||
/// \brief Check if \p T is an enum
|
||||
/// \tparam T type to check
|
||||
template<typename T> struct is_enum
|
||||
: bool_constant<FENNEC_BUILTIN_IS_ENUM(T)> {};
|
||||
|
||||
///
|
||||
/// \brief Check if \p T is a class
|
||||
/// \tparam T type to check
|
||||
template<typename T> constexpr size_t is_enum_v = is_enum<T>::value;
|
||||
|
||||
|
||||
|
||||
// fennec::is_union ====================================================================================================
|
||||
|
||||
///
|
||||
/// \brief Check if \p T is a union
|
||||
/// \tparam T type to check
|
||||
template<typename T> struct is_union
|
||||
: bool_constant<FENNEC_BUILTIN_IS_UNION(T)> {};
|
||||
|
||||
///
|
||||
/// \brief Check if \p T is a class
|
||||
/// \tparam T type to check
|
||||
template<typename T> constexpr size_t is_union_v = is_union<T>::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<typename T> struct is_class
|
||||
: bool_constant<FENNEC_BUILTIN_IS_CLASS(T)> {};
|
||||
|
||||
///
|
||||
/// \brief check if \p T is a class
|
||||
/// \brief Check if \p T is a class
|
||||
/// \tparam T type to check
|
||||
template<typename T> constexpr size_t is_class_v = is_class<T>::value;
|
||||
|
||||
|
||||
|
||||
// fennec::is_function ====================================================================================================
|
||||
|
||||
///
|
||||
/// \brief Check if \p T is a class
|
||||
/// \tparam T type to check
|
||||
template<typename T> struct is_function
|
||||
: bool_constant<FENNEC_BUILTIN_IS_FUNCTION(T)> {};
|
||||
|
||||
///
|
||||
/// \brief Check if \p T is a class
|
||||
/// \tparam T type to check
|
||||
template<typename T> constexpr size_t is_function_v = is_function<T>::value;
|
||||
|
||||
|
||||
|
||||
// Integral Types ======================================================================================================
|
||||
|
||||
|
||||
@@ -532,7 +579,7 @@ template<typename T> constexpr size_t is_class_v = is_class<T>::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<typename T> struct is_bool
|
||||
: detail::_is_bool<remove_cvr_t<T>>{};
|
||||
|
||||
///
|
||||
/// \brief shorthand for ```is_bool<T>::value```
|
||||
/// \brief Shorthand for ```is_bool<T>::value```
|
||||
/// \tparam T type to check
|
||||
template<typename T> constexpr bool_t is_bool_v = is_bool<T>::value;
|
||||
|
||||
|
||||
|
||||
// fennec::is_integral =================================================================================================
|
||||
|
||||
///
|
||||
/// \brief check if \p T is of an integral
|
||||
/// \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<typename T> struct is_integral
|
||||
: detail::_is_integral<remove_cvr_t<T>> {};
|
||||
|
||||
///
|
||||
/// \brief shorthand for ```is_integral<T>::value```
|
||||
/// \brief Shorthand for ```is_integral<T>::value```
|
||||
/// \tparam T type to check
|
||||
template<typename T> constexpr bool_t is_integral_v = is_integral<T>::value;
|
||||
|
||||
|
||||
|
||||
// fennec::is_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<typename T> struct is_signed
|
||||
: detail::_is_signed<remove_cvr_t<T>> {};
|
||||
|
||||
///
|
||||
/// \brief shorthand for ```is_signed<T>::value```
|
||||
/// \brief Shorthand for ```is_signed<T>::value```
|
||||
/// \tparam T type to check
|
||||
template<typename T> constexpr bool_t is_signed_v = is_signed<T>::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<typename T> struct is_unsigned
|
||||
: detail::_is_unsigned<remove_cvr_t<T>> {};
|
||||
|
||||
///
|
||||
/// \brief shorthand for ```is_unsigned<T>::value```
|
||||
/// \brief Shorthand for ```is_unsigned<T>::value```
|
||||
/// \tparam T type to check
|
||||
template<typename T> constexpr bool_t is_unsigned_v = is_unsigned<T>::value;
|
||||
|
||||
@@ -590,15 +649,15 @@ template<typename T> constexpr bool_t is_unsigned_v = is_unsigned<T>::value;
|
||||
// Floating Point Types ================================================================================================
|
||||
|
||||
///
|
||||
/// \brief check if \p T is of a floating point type
|
||||
/// \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<typename T> struct is_floating_point
|
||||
: detail::_is_floating_point<remove_cvr_t<T>>{};
|
||||
|
||||
///
|
||||
/// \brief shorthand for ```is_floating_point<T>::value```
|
||||
/// \brief Shorthand for ```is_floating_point<T>::value```
|
||||
/// \tparam T type to check
|
||||
template<typename T> constexpr bool_t is_floating_point_v = is_floating_point<T> {};
|
||||
|
||||
@@ -606,24 +665,69 @@ template<typename T> constexpr bool_t is_floating_point_v = is_floating_point<T>
|
||||
// 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<typename T> struct is_pointer
|
||||
: detail::_is_pointer<remove_cvr_t<T>>{};
|
||||
|
||||
///
|
||||
/// \brief shorthand for ```is_floating_point<T>::value```
|
||||
/// \brief Shorthand for ```is_pointer<T>::value```
|
||||
/// \tparam T type to check
|
||||
template<typename T> constexpr bool_t is_pointer_v = is_pointer<T> {};
|
||||
|
||||
|
||||
// Reference Types =======================================================================================================
|
||||
|
||||
///
|
||||
/// \brief Check if \p T is of a floating point type
|
||||
///
|
||||
/// \details Checks if type `T` is a floating point type and store it in `is_same::value`.
|
||||
/// \tparam T type to check
|
||||
template<typename T> struct is_reference
|
||||
: detail::_is_reference<T>{};
|
||||
|
||||
///
|
||||
/// \brief Shorthand for ```is_floating_point<T>::value```
|
||||
/// \tparam T type to check
|
||||
template<typename T> constexpr bool_t is_reference_v = is_reference<T> {};
|
||||
|
||||
|
||||
|
||||
///
|
||||
/// \brief Check if \p T is of a floating point type
|
||||
///
|
||||
/// \details Checks if type `T` is a floating point type and store it in `is_same::value`.
|
||||
/// \tparam T type to check
|
||||
template<typename T> struct is_lvalue_reference
|
||||
: detail::_is_lvalue_reference<T>{};
|
||||
|
||||
///
|
||||
/// \brief Shorthand for ```is_floating_point<T>::value```
|
||||
/// \tparam T type to check
|
||||
template<typename T> constexpr bool_t is_lvalue_reference_v = is_lvalue_reference<T> {};
|
||||
|
||||
|
||||
///
|
||||
/// \brief Check if \p T is of a floating point type
|
||||
///
|
||||
/// \details Checks if type `T` is a floating point type and store it in `is_same::value`.
|
||||
/// \tparam T type to check
|
||||
template<typename T> struct is_rvalue_reference
|
||||
: detail::_is_rvalue_reference<T>{};
|
||||
|
||||
///
|
||||
/// \brief Shorthand for ```is_floating_point<T>::value```
|
||||
/// \tparam T type to check
|
||||
template<typename T> constexpr bool_t is_rvalue_reference_v = is_rvalue_reference<T> {};
|
||||
|
||||
|
||||
|
||||
// Arithmetic Types ====================================================================================================
|
||||
|
||||
///
|
||||
/// \brief check if \p T is an arithmetic type
|
||||
/// \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<typename T> struct is_arithmetic
|
||||
: bool_constant<is_integral_v<T> or is_floating_point_v<T>>{};
|
||||
|
||||
///
|
||||
/// \brief shorthand for ```is_arithmetic<T>::value```
|
||||
/// \brief Shorthand for ```is_arithmetic<T>::value```
|
||||
/// \tparam T type to check
|
||||
template<typename T> constexpr bool_t is_arithmetic_v = is_arithmetic<T>::value;
|
||||
|
||||
|
||||
|
||||
// Arithmetic Types ====================================================================================================
|
||||
|
||||
///
|
||||
/// \brief Check if \p T is an arithmetic type
|
||||
///
|
||||
/// \details Checks if type `T` is a built-in type with arithmetic operators and store it in `is_same::value`.
|
||||
/// \tparam T type to check
|
||||
template<typename T> struct is_scalar
|
||||
: bool_constant<is_arithmetic_v<T> or is_enum_v<T> or is_pointer_v<T>>{};
|
||||
|
||||
///
|
||||
/// \brief Shorthand for ```is_scalar<T>::value```
|
||||
/// \tparam T type to check
|
||||
template<typename T> constexpr bool_t is_scalar_v = is_scalar<T>::value;
|
||||
|
||||
|
||||
// fennec::is_fundamental ==============================================================================================
|
||||
|
||||
///
|
||||
/// \brief check if \p T is a fundamental type, i.e. arithmetic, void, or nullptr_t
|
||||
/// \brief Check if \p T is a fundamental type, i.e. arithmetic, void, or nullptr_t
|
||||
/// \tparam T type to check
|
||||
template<typename T> struct is_fundamental
|
||||
: bool_constant<is_arithmetic_v<T> || is_void_v<T> || is_null_pointer_v<T>>{};
|
||||
|
||||
///
|
||||
/// \brief shorthand for ```is_fundamental<T>::value```
|
||||
/// \brief Shorthand for ```is_fundamental<T>::value```
|
||||
/// \tparam T type to check
|
||||
template<typename T> constexpr bool_t is_fundamental_v = is_fundamental<T>::value;
|
||||
|
||||
@@ -653,7 +774,7 @@ template<typename T> constexpr bool_t is_fundamental_v = is_fundamental<T>::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<typename T0, typename T1> struct is_same : false_type {};
|
||||
template<typename T> struct is_same<T, T> : true_type {};
|
||||
|
||||
///
|
||||
/// \brief shorthand for ```is_same<T0, T1>::value```
|
||||
/// \brief Shorthand for ```is_same<T0, T1>::value```
|
||||
/// \tparam T0 first type to check
|
||||
/// \tparam T1 second type to check
|
||||
template<typename T0, typename T1> constexpr bool_t is_same_v = is_same<T0, T1> {};
|
||||
@@ -672,63 +793,63 @@ template<typename T0, typename T1> constexpr bool_t is_same_v = is_same<T0, T1>
|
||||
// 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<typename T> struct is_complete : detail::_is_complete<T>::type {};
|
||||
|
||||
///
|
||||
/// \brief shorthand for `is_complete<TypeT0, TypeT1>::value`
|
||||
/// \brief Shorthand for `is_complete<TypeT0, TypeT1>::value`
|
||||
/// \tparam T type to check
|
||||
template<typename T> constexpr bool_t is_complete_v = is_complete<T>{};
|
||||
|
||||
// fennec::is_iterable ==============================================================================================
|
||||
|
||||
///
|
||||
/// \brief check if type `T` is iterable
|
||||
/// \brief Check if type `T` is iterable
|
||||
///
|
||||
/// \details Checks if `T`
|
||||
/// \tparam T type to check
|
||||
template<typename T> struct is_iterable : decltype(detail::_is_iterable<T>(0)) {};
|
||||
|
||||
///
|
||||
/// \brief shorthand for `is_iterable<TypeT0, TypeT1>::value`
|
||||
/// \brief Shorthand for `is_iterable<TypeT0, TypeT1>::value`
|
||||
/// \tparam T type to check
|
||||
template<typename T> constexpr bool_t is_iterable_v = is_iterable<T>{};
|
||||
|
||||
// fennec::is_indexable ==============================================================================================
|
||||
|
||||
///
|
||||
/// \brief check if type `T` is indexable
|
||||
/// \brief Check if type `T` is indexable
|
||||
///
|
||||
/// \details Checks if `T`
|
||||
/// \tparam T type to check
|
||||
template<typename T> struct is_indexable : decltype(detail::_is_indexable<T>(0)) {};
|
||||
|
||||
///
|
||||
/// \brief shorthand for `is_indexable<TypeT0, TypeT1>::value`
|
||||
/// \brief Shorthand for `is_indexable<TypeT0, TypeT1>::value`
|
||||
/// \tparam T type to check
|
||||
template<typename T> constexpr bool_t is_indexable_v = is_indexable<T>{};
|
||||
|
||||
// fennec::is_mappable ==============================================================================================
|
||||
|
||||
///
|
||||
/// \brief check if type `T` is mappable
|
||||
/// \brief Check if type `T` is mappable
|
||||
///
|
||||
/// \details Checks if `T`
|
||||
/// \tparam T type to check
|
||||
template<typename T> struct is_mappable : decltype(detail::_is_mappable<T>(0)) {};
|
||||
|
||||
///
|
||||
/// \brief shorthand for `is_mappable<TypeT0, TypeT1>::value`
|
||||
/// \brief Shorthand for `is_mappable<TypeT0, TypeT1>::value`
|
||||
/// \tparam T type to check
|
||||
template<typename T> constexpr bool_t is_mappable_v = is_mappable<T>{};
|
||||
|
||||
// fennec::is_convertible ==============================================================================================
|
||||
|
||||
///
|
||||
/// \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<typename FromT, typename ToT> struct is_convertible
|
||||
: bool_constant<FENNEC_BUILTIN_IS_CONVERTIBLE(FromT, ToT)> {};
|
||||
|
||||
///
|
||||
/// \brief shorthand for `can_convert<TypeT0, TypeT1>::value`
|
||||
/// \brief Shorthand for `can_convert<TypeT0, TypeT1>::value`
|
||||
/// \param FromT First type
|
||||
/// \param ToT Second type
|
||||
template<typename FromT, typename ToT> constexpr bool_t is_convertible_v = is_convertible<FromT, ToT>{};
|
||||
@@ -779,7 +900,7 @@ template<typename ClassT> struct is_default_constructible
|
||||
|
||||
///
|
||||
/// \brief Shorthand for `is_default_constructible<ClassT>::value`
|
||||
template<typename ClassT, typename...ArgsT> constexpr bool_t is_default_constructible_v = is_default_constructible<ClassT>{};
|
||||
template<typename ClassT> constexpr bool_t is_default_constructible_v = is_default_constructible<ClassT>{};
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <fennec/platform/interface/fwd.h>
|
||||
#include <fennec/platform/interface/window.h>
|
||||
#include <fennec/rtti/enable.h>
|
||||
#include <fennec/rtti/singleton.h>
|
||||
#include <fennec/rtti/detail/_this_t.h>
|
||||
|
||||
/*
|
||||
@@ -62,12 +63,12 @@
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
class platform {
|
||||
class platform : singleton<platform*> {
|
||||
public:
|
||||
using shared_object = struct shared_object;
|
||||
using symbol = void*;
|
||||
|
||||
platform() = default;
|
||||
platform();
|
||||
virtual ~platform() = default;
|
||||
platform(const platform&) = delete;
|
||||
|
||||
|
||||
@@ -32,6 +32,9 @@ public:
|
||||
void initialize() override;
|
||||
|
||||
void shutdown() override;
|
||||
|
||||
FENNEC_RTTI_CLASS_ENABLE(unix_platform) {
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -35,7 +35,9 @@ public:
|
||||
symbol find_symbol(shared_object* obj, const cstring& name) override;
|
||||
|
||||
private:
|
||||
FENNEC_RTTI_CLASS_ENABLE(platform) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -31,4 +31,17 @@
|
||||
#ifndef FENNEC_RTTI_FORWARD_H
|
||||
#define FENNEC_RTTI_FORWARD_H
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
class function;
|
||||
struct vtypelist;
|
||||
template<typename...> struct typelist;
|
||||
|
||||
struct type;
|
||||
struct type_data;
|
||||
struct type_storage;
|
||||
|
||||
}
|
||||
|
||||
#endif // FENNEC_RTTI_FORWARD_H
|
||||
52
include/fennec/rtti/singleton.h
Normal file
52
include/fennec/rtti/singleton.h
Normal file
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
///
|
||||
/// \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<typename T>
|
||||
struct singleton {
|
||||
static T& instance() requires(is_pointer_v<T>) {
|
||||
static T instance = nullptr;
|
||||
return instance;
|
||||
}
|
||||
|
||||
static T& instance() requires(is_default_constructible_v<T> and not is_pointer_v<T>) {
|
||||
static T instance;
|
||||
return instance;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FENNEC_RTTI_SINGLETON_H
|
||||
@@ -36,7 +36,7 @@
|
||||
#include <fennec/string/string.h>
|
||||
#include <fennec/memory/pointers.h>
|
||||
#include <fennec/rtti/typeid.h>
|
||||
#include <fennec/rtti/typelist.h>
|
||||
#include <fennec/rtti/forward.h>
|
||||
#include <fennec/rtti/detail/_type_name.h>
|
||||
|
||||
namespace fennec
|
||||
|
||||
85
include/fennec/rtti/type_registry.h
Normal file
85
include/fennec/rtti/type_registry.h
Normal file
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
///
|
||||
/// \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 <fennec/containers/priority_queue.h>
|
||||
#include <fennec/rtti/type.h>
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
template<typename BaseT, typename...ArgsT>
|
||||
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<entry, compare>;
|
||||
|
||||
template<typename T>
|
||||
static void register_type(size_t priority = 0) {
|
||||
_global_list().emplace(
|
||||
priority,
|
||||
type::get<T>(),
|
||||
_constructor_helper<ArgsT...>
|
||||
);
|
||||
}
|
||||
|
||||
static const entrylist_t& get_type_list() {
|
||||
return _global_list();
|
||||
}
|
||||
|
||||
private:
|
||||
static entrylist_t& _global_list() {
|
||||
static entrylist_t list;
|
||||
return list;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static BaseT* _constructor_helper(ArgsT&&...args) {
|
||||
return new T(fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FENNEC_RTTI_TYPE_REGISTRY_H
|
||||
@@ -32,13 +32,23 @@
|
||||
#define FENNEC_RTTI_TYPELIST_H
|
||||
|
||||
#include <fennec/lang/types.h>
|
||||
#include <fennec/rtti/type.h>
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
struct vtypelist {
|
||||
virtual ~vtypelist() = default;
|
||||
virtual dynarray<type> get() = 0;
|
||||
};
|
||||
|
||||
template<typename...TypesT>
|
||||
struct typelist {
|
||||
struct typelist : vtypelist {
|
||||
static constexpr size_t size = sizeof...(TypesT);
|
||||
|
||||
virtual dynarray<type> get() {
|
||||
return { type::get<TypesT>()... };
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user