// ---------------------------------------------------------------------------------------------------------------------
//  fennec, a free and open source game engine
//  Copyright © 2025 - 2026  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 fennec/lang/type_traits.h
/// \brief \ref fennec_lang_type_traits
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///

#ifndef FENNEC_LANG_TYPE_TRAITS_H
#define FENNEC_LANG_TYPE_TRAITS_H

///
/// \page fennec_lang_type_traits Type Traits
///
/// \brief Part of the fennec metaprogramming library. This header defines structures for accessing traits of types
///        at compile time.
///
/// \code #include <fennec/lang/type_traits.h> \endcode
///
///
///
/// \section fennec_lang_type_traits_section_primary_type_categories Primary Type Categories
///
/// <table width-"100%" class-"fieldtable" id-"table_fennec_lang_type_traits_primary_categories">
/// <tr><th style-"vertical-align: top">Syntax
///     <th style-"vertical-align: top">Description
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_void "is_void<TypeT>::value"<br>
///         \ref fennec::is_void_v "is_void_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_void
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_null_pointer "is_null_pointer<TypeT>::value"<br>
///         \ref fennec::is_null_pointer_v "is_null_pointer_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_null_pointer
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_bool "is_bool<TypeT>::value"<br>
///         \ref fennec::is_bool_v "is_bool_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_bool
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_integral "is_integral<TypeT>::value"<br>
///         \ref fennec::is_integral_v "is_integral_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_integral
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_floating_point "is_floating_point<TypeT>::value"<br>
///         \ref fennec::is_floating_point_v "is_floating_point_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_floating_point
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_array "is_array<TypeT>::value"<br>
///         \ref fennec::is_array_v "is_array_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_array
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_enum "is_enum<TypeT>::value"<br>
///         \ref fennec::is_enum_v "is_enum_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_enum
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_union "is_union<TypeT>::value"<br>
///         \ref fennec::is_union_v "is_union_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_union
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_class "is_class<TypeT>::value"<br>
///         \ref fennec::is_class_v "is_class_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_class
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_function "is_function<TypeT>::value"<br>
///         \ref fennec::is_function_v "is_function_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_function
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_pointer "is_pointer<TypeT>::value"<br>
///         \ref fennec::is_pointer_v "is_pointer_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_pointer
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_lvalue_reference "is_lvalue_reference<TypeT>::value"<br>
///         \ref fennec::is_lvalue_reference_v "is_lvalue_reference_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_lvalue_reference
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_rvalue_reference "is_rvalue_reference<TypeT>::value"<br>
///         \ref fennec::is_rvalue_reference_v "is_rvalue_reference_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_rvalue_reference
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_member_object_pointer "is_member_object_pointer<TypeT>::value"<br>
///         \ref fennec::is_member_object_pointer_v "is_member_object_pointer_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_member_object_pointer
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_member_function_pointer "is_member_function_pointer<TypeT>::value"<br>
///         \ref fennec::is_member_function_pointer_v "is_member_function_pointer_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_member_function_pointer
///
/// </table>
///
///
///
/// \section fennec_lang_type_traits_section_composite_type_categories Composite Type Categories
///
/// <table width-"100%" class-"fieldtable" id-"table_fennec_lang_type_traits_composite_categories">
/// <tr><th style-"vertical-align: top">Syntax
///     <th style-"vertical-align: top">Description
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_arithmetic "is_arithmetic<TypeT>::value"<br>
///         \ref fennec::is_arithmetic_v "is_arithmetic_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_arithmetic
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_fundamental "is_fundamental<TypeT>::value"<br>
///         \ref fennec::is_fundamental_v "is_fundamental_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_fundamental
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_scalar "is_scalar<TypeT>::value"<br>
///         \ref fennec::is_scalar_v "is_scalar_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_scalar
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_object "is_object<TypeT>::value"<br>
///         \ref fennec::is_object_v "is_object_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_object
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_compound "is_compound<TypeT>::value"<br>
///         \ref fennec::is_compound_v "is_compound_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_compound
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_reference "is_reference<TypeT>::value"<br>
///         \ref fennec::is_reference_v "is_reference_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_reference
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_member_pointer "is_member_pointer<TypeT>::value"<br>
///         \ref fennec::is_member_pointer_v "is_member_pointer_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_member_pointer
///
/// </table>
///
///
///
/// \section fennec_lang_type_traits_section_type_properties Type Properties
///
/// <table width-"100%" class-"fieldtable" id-"table_fennec_lang_type_traits_type_properties">
/// <tr><th style-"vertical-align: top">Syntax
///     <th style-"vertical-align: top">Description
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_const "is_const<TypeT>::value"<br>
///         \ref fennec::is_const_v "is_const_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_const
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_volatile "is_volatile<TypeT>::value"<br>
///         \ref fennec::is_volatile_v "is_volatile_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_volatile
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_trivial "is_trivial<TypeT>::value"<br>
///         \ref fennec::is_trivial_v "is_trivial_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_trivial
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_trivially_copyable "is_trivially_copyable<TypeT>::value"<br>
///         \ref fennec::is_trivially_copyable_v "is_trivially_copyable_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_trivially_copyable
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_standard_layout "is_standard_layout<TypeT>::value"<br>
///         \ref fennec::is_standard_layout_v "is_standard_layout_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_standard_layout
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::has_unique_object_representations "has_unique_object_representations<TypeT>::value"<br>
///         \ref fennec::has_unique_object_representations_v "has_unique_object_representations_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::has_unique_object_representations
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_empty "is_empty<TypeT>::value"<br>
///         \ref fennec::is_empty_v "is_empty_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_empty
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_polymorphic "is_polymorphic<TypeT>::value"<br>
///         \ref fennec::is_polymorphic_v "is_polymorphic_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_polymorphic
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_abstract "is_abstract<TypeT>::value"<br>
///         \ref fennec::is_abstract_v "is_abstract_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_abstract
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_complete "is_complete<TypeT>::value"<br>
///         \ref fennec::is_complete_v "is_complete_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_complete
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_final "is_final<TypeT>::value"<br>
///         \ref fennec::is_final_v "is_final_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_final
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_aggregate "is_aggregate<TypeT>::value"<br>
///         \ref fennec::is_aggregate_v "is_aggregate_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_aggregate
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_signed "is_signed<TypeT>::value"<br>
///         \ref fennec::is_signed_v "is_signed_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_signed
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_unsigned "is_unsigned<TypeT>::value"<br>
///         \ref fennec::is_unsigned_v "is_unsigned_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_unsigned
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_bounded_array "is_bounded_array<TypeT>::value"<br>
///         \ref fennec::is_bounded_array_v "is_bounded_array_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_bounded_array
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_unbounded_array "is_unbounded_array<TypeT>::value"<br>
///         \ref fennec::is_unbounded_array_v "is_unbounded_array_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_unbounded_array
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_scoped_enum "is_scoped_enum<TypeT>::value"<br>
///         \ref fennec::is_scoped_enum_v "is_scoped_enum_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_scoped_enum
///
/// </table>
///
///
///
/// \section fennec_lang_type_traits_section_supported_operations Supported Operations
///
/// <table width-"100%" class-"fieldtable" id-"table_fennec_lang_type_traits_supported_operations">
/// <tr><th style-"vertical-align: top">Syntax
///     <th style-"vertical-align: top">Description
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_convertible "is_convertible<TypeT0, TypeT1>::value"<br>
///         \ref fennec::is_convertible_v "is_convertible_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_convertible
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_constructible "is_constructible<ClassT, ArgsT...>::value"<br>
///         \ref fennec::is_constructible_v "is_constructible_v<ClassT, ArgsT...>"
///         \ref fennec::is_trivially_constructible "is_trivially_constructible<ClassT, ArgsT...>::value"<br>
///         \ref fennec::is_trivially_constructible_v "is_trivially_constructible_v<ClassT, ArgsT...>"
///         \ref fennec::is_nothrow_constructible "is_nothrow_constructible<ClassT, ArgsT...>::value"<br>
///         \ref fennec::is_nothrow_constructible_v "is_nothrow_constructible_v<ClassT, ArgsT...>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_constructible
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_default_constructible "is_default_constructible<ClassT, ArgsT...>::value"<br>
///         \ref fennec::is_default_constructible_v "is_default_constructible_v<ClassT, ArgsT...>"
///         \ref fennec::is_trivially_default_constructible "is_trivially_default_constructible<ClassT, ArgsT...>::value"<br>
///         \ref fennec::is_trivially_default_constructible_v "is_trivially_default_constructible_v<ClassT, ArgsT...>"
///         \ref fennec::is_nothrow_default_constructible "is_nothrow_default_constructible<ClassT, ArgsT...>::value"<br>
///         \ref fennec::is_nothrow_default_constructible_v "is_nothrow_default_constructible_v<ClassT, ArgsT...>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_default_constructible
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_copy_constructible "is_copy_constructible<ClassT, ArgsT...>::value"<br>
///         \ref fennec::is_copy_constructible_v "is_copy_constructible_v<ClassT, ArgsT...>"
///         \ref fennec::is_trivially_copy_constructible "is_trivially_copy_constructible<ClassT, ArgsT...>::value"<br>
///         \ref fennec::is_trivially_copy_constructible_v "is_trivially_copy_constructible_v<ClassT, ArgsT...>"
///         \ref fennec::is_nothrow_copy_constructible "is_nothrow_copy_constructible<ClassT, ArgsT...>::value"<br>
///         \ref fennec::is_nothrow_copy_constructible_v "is_nothrow_copy_constructible_v<ClassT, ArgsT...>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_copy_constructible
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_move_constructible "is_move_constructible<ClassT, ArgsT...>::value"<br>
///         \ref fennec::is_move_constructible_v "is_move_constructible_v<ClassT, ArgsT...>"
///         \ref fennec::is_trivially_move_constructible "is_trivially_move_constructible<ClassT, ArgsT...>::value"<br>
///         \ref fennec::is_trivially_move_constructible_v "is_trivially_move_constructible_v<ClassT, ArgsT...>"
///         \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">
///         \copydetails fennec::is_move_constructible
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_assignable "is_assignable<ClassT, ArgsT...>::value"<br>
///         \ref fennec::is_assignable_v "is_assignable_v<ClassT, ArgsT...>"
///         \ref fennec::is_trivially_assignable "is_trivially_assignable<ClassT, ArgsT...>::value"<br>
///         \ref fennec::is_trivially_assignable_v "is_trivially_assignable_v<ClassT, ArgsT...>"
///         \ref fennec::is_nothrow_assignable "is_nothrow_assignable<ClassT, ArgsT...>::value"<br>
///         \ref fennec::is_nothrow_assignable_v "is_nothrow_assignable_v<ClassT, ArgsT...>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_assignable
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_copy_assignable "is_copy_assignable<ClassT, ArgsT...>::value"<br>
///         \ref fennec::is_copy_assignable_v "is_copy_assignable_v<ClassT, ArgsT...>"
///         \ref fennec::is_trivially_copy_assignable "is_trivially_copy_assignable<ClassT, ArgsT...>::value"<br>
///         \ref fennec::is_trivially_copy_assignable_v "is_trivially_copy_assignable_v<ClassT, ArgsT...>"
///         \ref fennec::is_nothrow_copy_assignable "is_nothrow_copy_assignable<ClassT, ArgsT...>::value"<br>
///         \ref fennec::is_nothrow_copy_assignable_v "is_nothrow_copy_assignable_v<ClassT, ArgsT...>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_copy_assignable
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_move_assignable "is_move_assignable<ClassT, ArgsT...>::value"<br>
///         \ref fennec::is_move_assignable_v "is_move_assignable_v<ClassT, ArgsT...>"
///         \ref fennec::is_trivially_move_assignable "is_trivially_move_assignable<ClassT, ArgsT...>::value"<br>
///         \ref fennec::is_trivially_move_assignable_v "is_trivially_move_assignable_v<ClassT, ArgsT...>"
///         \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">
///         \copydetails fennec::is_move_assignable
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_destructible "is_destructible<ClassT, ArgsT...>::value"<br>
///         \ref fennec::is_destructible_v "is_destructible_v<ClassT, ArgsT...>"
///         \ref fennec::is_trivially_destructible "is_trivially_destructible<ClassT, ArgsT...>::value"<br>
///         \ref fennec::is_trivially_destructible_v "is_trivially_destructible_v<ClassT, ArgsT...>"
///         \ref fennec::is_nothrow_destructible "is_nothrow_destructible<ClassT, ArgsT...>::value"<br>
///         \ref fennec::is_nothrow_destructible_v "is_nothrow_destructible_v<ClassT, ArgsT...>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_destructible
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::has_virtual_destructor "has_virtual_destructor<ClassT, ArgsT...>::value"<br>
///         \ref fennec::has_virtual_destructor_v "has_virtual_destructor_v<ClassT, ArgsT...>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::has_virtual_destructor
///
/// </table>
///
///
///
/// \section fennec_lang_type_traits_section_type_relationships Type Relationships
///
/// <table width-"100%" class-"fieldtable" id-"table_fennec_lang_type_traits_type_relationships">
/// <tr><th style-"vertical-align: top">Syntax
///     <th style-"vertical-align: top">Description
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_same "is_same<TypeT>::value"<br>
///         \ref fennec::is_same_v "is_same_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_same
///
/// <tr><td width-"50%" style-"vertical-align: top"> <br>
///         \ref fennec::is_base_of "is_base_of<TypeT>::value"<br>
///         \ref fennec::is_base_of_v "is_base_of_v<TypeT>"
///     <td width-"50%" style-"vertical-align: top">
///         \copydetails fennec::is_base_of
///
/// </table>
///

#include <fennec/lang/intrinsics.h>
#include <fennec/lang/type_transforms.h>
#include <fennec/lang/detail/_type_traits.h>

namespace fennec
{

///
/// \brief metaprogramming helper for determining if a function is consteval
/// \returns \emph{true} if under `consteval`, \emph{false} otherwise
constexpr inline bool is_constant_evaluated() noexcept {
	if consteval {
		return true;
	} else {
		return false;
	}
}



// Primary Type Categories =============================================================================================


// fennec::is_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
template<typename T> struct is_void
	: detail::_is_void<remove_cvref_t<T>>{};

///
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
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
///
/// \details Stores a boolean value in `is_null_pointer::value`, representing whether the provided type is of base type nullptr_t.
/// \tparam T type to check
template<typename T> struct is_null_pointer
	: detail::_is_null_pointer<remove_cvref_t<T>>{};

///
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
template<typename T> constexpr bool_t is_null_pointer_v = is_null_pointer<T>::value;



// fennec::is_bool -----------------------------------------------------------------------------------------------------

///
/// \brief Check if \p T is of type bool
///
/// \details Stores a boolean value in `is_bool::value`, representing whether the provided type is of base type bool.
/// \tparam T type to check
template<typename T> struct is_bool
	: detail::_is_bool<remove_cvref_t<T>>{};

///
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
template<typename T> constexpr bool_t is_bool_v = is_bool<T>::value;



// fennec::is_integral -------------------------------------------------------------------------------------------------

///
/// \brief Check if \p T is of an integral
///
/// \details Stores a boolean value in `is_integral::value`, representing whether the provided type is of a base integer type.
/// \tparam T type to check
template<typename T> struct is_integral
	: detail::_is_integral<remove_cvref_t<T>> {};

///
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
template<typename T> constexpr bool_t is_integral_v = is_integral<T>::value;



// fennec::is_floating_point -------------------------------------------------------------------------------------------

///
/// \brief Check if \p T is of a floating point type
///
/// \details Stores a boolean value in `is_floating_point::value`, representing whether the provided type is of a base floating point type.
/// \tparam T type to check
template<typename T> struct is_floating_point
	: detail::_is_floating_point<remove_cvref_t<T>>{};

///
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
template<typename T> constexpr bool_t is_floating_point_v = is_floating_point<T> {};



// fennec::is_array ----------------------------------------------------------------------------------------------------

#if FENNEC_HAS_BUILTIN_IS_ARRAY

///
/// \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)> {};

#else

///
/// \brief Check if \p T is of an array type
/// \tparam T type to check
template<typename T> struct is_array
	: false_type {};

// overload for a sized array type
template<typename T, size_t N> struct is_array<T[N]>
	: true_type {};

// overload for a generic array type
template<typename T> struct is_array<T[]>
	: true_type {};

#endif

///
/// \brief Shorthand for `(.*?)`
/// \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
/// \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
/// \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;



// fennec::is_pointer --------------------------------------------------------------------------------------------------

///
/// \brief Check if \p T is of a pointer type
///
/// \details Stores a boolean value in `is_pointer::value`, representing whether the provided type is of a base pointer type.
/// \tparam T type to check
template<typename T> struct is_pointer
	: detail::_is_pointer<remove_cvref_t<T>>{};

///
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
template<typename T> constexpr bool_t is_pointer_v = is_pointer<T> {};



// fennec::is_lvalue_reference -----------------------------------------------------------------------------------------

///
/// \brief Check if \p T is of a floating point type
///
/// \details Checks if type \emph{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 `(.*?)`
/// \tparam T type to check
template<typename T> constexpr bool_t is_lvalue_reference_v = is_lvalue_reference<T> {};



// fennec::is_rvalue_reference -----------------------------------------------------------------------------------------

///
/// \brief Check if \p T is of a floating point type
///
/// \details Checks if type \emph{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 `(.*?)`
/// \tparam T type to check
template<typename T> constexpr bool_t is_rvalue_reference_v = is_rvalue_reference<T> {};



// fennec::is_member_function_pointer ----------------------------------------------------------------------------------

///
/// \brief Check if \p T is a pointer to a member function
///
/// \details Checks if type \emph{T} is pointer to a member function and store it in `is_member_function_pointer::value`.
/// \tparam T type to check
template<typename T> struct is_member_function_pointer
	: bool_constant<FENNEC_BUILTIN_IS_MEMBER_FUNCTION_POINTER(T)> {};

///
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
template<typename T> constexpr bool_t is_member_function_pointer_v = is_member_function_pointer<T> {};



// fennec::is_member_object_pointer ------------------------------------------------------------------------------------

///
/// \brief Check if \p T is a pointer to a member object
///
/// \details Checks if type \emph{T} is pointer to a member object and store it in `is_member_object_pointer::value`.
/// \tparam T type to check
template<typename T> struct is_member_object_pointer
	: bool_constant<FENNEC_BUILTIN_IS_MEMBER_OBJECT_POINTER(T)> {};

///
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
template<typename T> constexpr bool_t is_member_object_pointer_v = is_member_object_pointer<T> {};





// Composite Type Categories ===========================================================================================


// fennec::is_arithmetic -----------------------------------------------------------------------------------------------

///
/// \brief Check if \p T is an arithmetic type
///
/// \details Checks if type \emph{T} is a built-in type with arithmetic operators and store it in `is_same::value`.
/// \tparam T type to check
template<typename T> struct is_arithmetic
	: bool_constant<is_integral_v<T> or is_floating_point_v<T>>{};

///
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
template<typename T> constexpr bool_t is_arithmetic_v = is_arithmetic<T>::value;


// fennec::is_fundamental ----------------------------------------------------------------------------------------------

///
/// \brief Check if \p T is a fundamental type, i.e. arithmetic, void, or nullptr_t
/// \tparam T type to check
template<typename T> struct is_fundamental
	: bool_constant<is_arithmetic_v<T> or is_void_v<T> or is_null_pointer_v<T>>{};

///
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
template<typename T> constexpr bool_t is_fundamental_v = is_fundamental<T>::value;



// fennec::is_scalar ---------------------------------------------------------------------------------------------------

///
/// \brief Check if \p T is an arithmetic type
///
/// \details Checks if type \emph{T} is a built-in type with arithmetic operators and store it in `is_scalar::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 `(.*?)`
/// \tparam T type to check
template<typename T> constexpr bool_t is_scalar_v = is_scalar<T>::value;



// fennec::is_object ---------------------------------------------------------------------------------------------------

///
/// \brief Check if \p T is an object
///
/// \details Checks if type \emph{T} is an object and store it in `is_object::value`.
/// \tparam T type to check
template<typename T> struct is_object : bool_constant<FENNEC_BUILTIN_IS_OBJECT(T)> {};

///
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
template<typename T> constexpr bool_t is_object_v = is_object<T>::value;



// fennec::is_compound -------------------------------------------------------------------------------------------------

///
/// \brief Check if \p T is a object compound type
///
/// \details Checks if type \emph{T} is an object and store it in `is_compound::value`.
/// \tparam T type to check
template<typename T> struct is_compound : bool_constant<not is_fundamental_v<T>> {};

///
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
template<typename T> constexpr bool_t is_compound_v = is_compound<T>::value;



// fennec::is_reference ------------------------------------------------------------------------------------------------

///
/// \brief Check if \p T is of a reference type
///
/// \details Checks if type \emph{T} is a reference type and store it in `is_reference::value`.
/// \tparam T type to check
template<typename T> struct is_reference
	: detail::_is_reference<T>{};

///
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
template<typename T> constexpr bool_t is_reference_v = is_reference<T> {};



// fennec::is_member_pointer -------------------------------------------------------------------------------------------

///
/// \brief Check if \p T is a pointer to a member
///
/// \details Checks if type \emph{T} is pointer to a member and store it in `is_member_function_pointer::value`.
/// \tparam T type to check
template<typename T> struct is_member_pointer
	: bool_constant<FENNEC_BUILTIN_IS_MEMBER_POINTER(T)> {};

///
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
template<typename T> constexpr bool_t is_member_pointer_v = is_member_pointer<T> {};





// Type Properties =====================================================================================================


// fennec::is_const ----------------------------------------------------------------------------------------------------

///
/// \brief Check if \p T is of a const type
///
/// \details Checks if type \emph{T} is a const type and store it in `is_same::value`.
/// \tparam T type to check
template<typename T> struct is_const
	: detail::_is_const<T>{};

///
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
template<typename T> constexpr bool_t is_const_v = is_const<T> {};



// fennec::is_volatile -------------------------------------------------------------------------------------------------

///
/// \brief Check if \p T is of a volatile type
///
/// \details Checks if type \emph{T} is a volatile type and store it in `is_same::value`.
/// \tparam T type to check
template<typename T> struct is_volatile
	: detail::_is_volatile<T>{};

///
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
template<typename T> constexpr bool_t is_volatile_v = is_volatile<T> {};



// fennec::is_trivial --------------------------------------------------------------------------------------------------

///
/// \brief Check if type \emph{T} is trivial
///
/// \details Checks if \emph{T}
/// \tparam T type to check
template<typename T> struct is_trivial : bool_constant<FENNEC_BUILTIN_IS_TRIVIAL(T)> {};

///
/// \brief Shorthand for `is_trivial<T>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_trivial_v = is_trivial<T>{};



// fennec::is_trivially_copyable ---------------------------------------------------------------------------------------

///
/// \brief Check if type \emph{T} is trivially_copyable
///
/// \details Checks if \emph{T}
/// \tparam T type to check
template<typename T> struct is_trivially_copyable : bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_COPYABLE(T)> {};

///
/// \brief Shorthand for `is_trivially_copyable<T>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_trivially_copyable_v = is_trivially_copyable<T>{};



// fennec::is_standard_layout ------------------------------------------------------------------------------------------

///
/// \brief Check if type \emph{T} is standard_layout
///
/// \details Checks if \emph{T}
/// \tparam T type to check
template<typename T> struct is_standard_layout : bool_constant<FENNEC_BUILTIN_IS_STANDARD_LAYOUT(T)> {};

///
/// \brief Shorthand for `is_standard_layout<T>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_standard_layout_v = is_standard_layout<T>{};



// fennec::has_unique_object_representations ---------------------------------------------------------------------------

///
/// \brief Check if type \emph{T} has unique object representations
///
/// \details Checks if \emph{T}
/// \tparam T type to check
template<typename T> struct has_unique_object_representations
	: bool_constant<FENNEC_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS(remove_cv_t<T>)> {};

///
/// \brief Shorthand for `has_unique_object_representations<T>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t has_unique_object_representations_v = has_unique_object_representations<T>{};



// fennec::is_empty ----------------------------------------------------------------------------------------------------

///
/// \brief Check if type \emph{T} is empty
///
/// \details Checks if \emph{T}
/// \tparam T type to check
template<typename T> struct is_empty : bool_constant<FENNEC_BUILTIN_IS_EMPTY(T)> {};

///
/// \brief Shorthand for `is_empty<T>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_empty_v = is_empty<T>{};



// fennec::is_polymorphic ----------------------------------------------------------------------------------------------

///
/// \brief Check if type \emph{T} is polymorphic
///
/// \details Checks if \emph{T}
/// \tparam T type to check
template<typename T> struct is_polymorphic : bool_constant<FENNEC_BUILTIN_IS_POLYMORPHIC(T)> {};

///
/// \brief Shorthand for `is_polymorphic<T>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_polymorphic_v = is_polymorphic<T>{};



// fennec::is_abstract -------------------------------------------------------------------------------------------------

///
/// \brief Check if type \emph{T} is abstract
///
/// \details Checks if \emph{T}
/// \tparam T type to check
template<typename T> struct is_abstract : bool_constant<FENNEC_BUILTIN_IS_ABSTRACT(T)> {};

///
/// \brief Shorthand for `is_abstract<T>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_abstract_v = is_abstract<T>{};



// fennec::is_complete -------------------------------------------------------------------------------------------------

///
/// \brief Check if type \emph{T} is complete
///
/// \details Checks if \emph{T}
/// \tparam T type to check
template<typename T> struct is_complete : detail::_is_complete<T>::type {};

///
/// \brief Shorthand for `is_complete<T>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_complete_v = is_complete<T>{};



// fennec::is_final -------------------------------------------------------------------------------------------------

///
/// \brief Check if type \emph{T} is final
///
/// \details Checks if \emph{T}
/// \tparam T type to check
template<typename T> struct is_final : bool_constant<FENNEC_BUILTIN_IS_FINAL(T)> {};

///
/// \brief Shorthand for `is_final<T>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_final_v = is_final<T>{};



// fennec::is_aggregate -------------------------------------------------------------------------------------------------

///
/// \brief Check if type \emph{T} is aggregate
///
/// \details Checks if \emph{T}
/// \tparam T type to check
template<typename T> struct is_aggregate : bool_constant<FENNEC_BUILTIN_IS_AGGREGATE(T)> {};

///
/// \brief Shorthand for `is_aggregate<T>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_aggregate_v = is_aggregate<T>{};



// fennec::is_signed -------------------------------------------------------------------------------------------------


///
/// \brief Check if \p T is of a signed integral
///
/// \details Checks if type \emph{T} is a signed type i.e. \math{\textbf{T(-1)} < \textbf{T(0)}} and stores it in `is_same::value`.
/// \tparam T type to check
template<typename T> struct is_signed
	: detail::_is_signed<remove_cvref_t<T>> {};

///
/// \brief Shorthand for `(.*?)`
/// \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
///
/// \details Checks if type \emph{T} is an unsigned type i.e. \math{\textbf{T(-1)} > \textbf{T(0)}} and stores it in `is_same::value`.
/// \tparam T type to check
template<typename T> struct is_unsigned
	: detail::_is_unsigned<remove_cvref_t<T>> {};

///
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
	template<typename T> constexpr bool_t is_unsigned_v = is_unsigned<T>::value;



// fennec::is_bounded_array --------------------------------------------------------------------------------------------

///
/// \brief Check if \p T is of an bounded type
/// \tparam T type to check
template<typename T> struct is_bounded_array
	: false_type {};

// overload for a sized array type
template<typename T, size_t N> struct is_bounded_array<T[N]>
	: true_type {};

///
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
template<typename T> constexpr bool_t is_bounded_array_v = is_bounded_array<T>::value;



// fennec::is_unbounded_array ------------------------------------------------------------------------------------------

///
/// \brief Check if \p T is of an unbounded type
/// \tparam T type to check
template<typename T> struct is_unbounded_array
	: false_type {};

// overload for a sized array type
template<typename T> struct is_unbounded_array<T[]>
	: true_type {};

///
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
template<typename T> constexpr bool_t is_unbounded_array_v = is_unbounded_array<T>::value;



// fennec::is_scoped_enum ------------------------------------------------------------------------------------------

#if FENNEC_HAS_BUILTIN_SCOPED_ENUM

///
/// \brief Check if \p T is of a scoped enum type
/// \tparam T type to check
template<typename T> struct is_scoped_enum
	: bool_constant<FENNEC_BUILTIN_IS_SCOPED_ENUM(T)> {};

#else

///
/// \brief Check if \p T is of an unbounded type
/// \tparam T type to check
template<typename T> struct is_scoped_enum
	: false_type {};

#ifndef FENNEC_DOXYGEN
// true case
template<typename T>
	requires __is_enum(T) and requires(remove_cv_t<T> test) { test = test; } // fails if incomplete
struct is_scoped_enum<T>
	: bool_constant<!requires(T test, void(*testf)(int)) { testf(test); }> { 
};
#endif


#endif

///
/// \brief Shorthand for `(.*?)`
/// \tparam T type to check
template<typename T> constexpr bool_t is_scoped_enum_v = is_scoped_enum<T>::value;





// Supported Operations ================================================================================================


// fennec::is_convertible ----------------------------------------------------------------------------------------------

///
/// \brief Check if type \emph{T0} can be converted \emph{T1}
///
/// \details Checks if \emph{TypeT0}
/// \tparam FromT First type
/// \tparam ToT Second type
template<typename FromT, typename ToT> struct is_convertible
	: bool_constant<FENNEC_BUILTIN_IS_CONVERTIBLE(FromT, ToT)> {};

///
/// \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>{};



// fennec::is_constructible --------------------------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} can be constructed with \emph{ArgsT...}, i.e. `ClassT(ArgsT...)`.
///        This may be read as "is \emph{ClassT} constructible with \emph{ArgsT}"
/// \tparam ClassT The class type to test
/// \tparam ArgsT The arguments for the specific constructor
template<typename ClassT, typename...ArgsT> struct is_constructible
	: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, ArgsT...)> {};

///
/// \brief Shorthand for `is_constructible<ClassT, ArgsT...>::value`
template<typename ClassT, typename...ArgsT> constexpr bool_t is_constructible_v = is_constructible<ClassT, ArgsT...>{};



// fennec::is_trivially_constructible ----------------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} is trivially constructible
/// \tparam ClassT The class type to test
/// \tparam ArgsT The arguments for the specific constructor
template<typename ClassT, typename...ArgsT> struct is_trivially_constructible
	: bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE(ClassT, ArgsT...)> {};

///
/// \brief Shorthand for `is_trivially_constructible<ClassT, ArgsT...>::value`
template<typename ClassT> constexpr bool_t is_trivially_constructible_v = is_trivially_constructible<ClassT>{};



// fennec::is_nothrow_constructible ------------------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} is nothrow constructible
/// \tparam ClassT The class type to test
/// \tparam ArgsT The arguments for the specific constructor
template<typename ClassT, typename...ArgsT> struct is_nothrow_constructible
	: bool_constant<FENNEC_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE(ClassT, ArgsT...)> {};

///
/// \brief Shorthand for `is_nothrow_constructible<ClassT, ArgsT...>::value`
template<typename ClassT> constexpr bool_t is_nothrow_constructible_v = is_nothrow_constructible<ClassT>{};



// fennec::is_default_constructible ------------------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} is default constructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_default_constructible
	: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT)> {};

///
/// \brief Shorthand for `is_default_constructible<ClassT>::value`
template<typename ClassT> constexpr bool_t is_default_constructible_v = is_default_constructible<ClassT>{};



// fennec::is_trivially_default_constructible --------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} is trivially default constructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_trivially_default_constructible
	: bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE(ClassT)> {};

///
/// \brief Shorthand for `is_trivially_default_constructible<ClassT>::value`
template<typename ClassT> constexpr bool_t is_trivially_default_constructible_v = is_trivially_default_constructible<ClassT>{};



// fennec::is_nothrow_default_constructible --------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} is nothrow default constructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_nothrow_default_constructible
	: bool_constant<FENNEC_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE(ClassT)> {};

///
/// \brief Shorthand for `is_nothrow_default_constructible<ClassT>::value`
template<typename ClassT> constexpr bool_t is_nothrow_default_constructible_v = is_nothrow_default_constructible<ClassT>{};



// fennec::is_copy_constructible ---------------------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} is copy constructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_copy_constructible
	: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {};

///
/// \brief Shorthand for `is_copy_constructible<ClassT>::value`
template<typename ClassT, typename...ArgsT> constexpr bool_t is_copy_constructible_v = is_copy_constructible<ClassT>{};



// fennec::is_trivially_copy_constructible -----------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} is trivially copy constructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_trivially_copy_constructible
	: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {};

///
/// \brief Shorthand for `is_trivially_copy_constructible<ClassT>::value`
	template<typename ClassT, typename...ArgsT> constexpr bool_t is_trivially_copy_constructible_v = is_trivially_copy_constructible<ClassT>{};



// fennec::is_nothrow_copy_constructible -------------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} is nothrow copy constructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_nothrow_copy_constructible
	: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {};

///
/// \brief Shorthand for `is_nothrow_copy_constructible<ClassT>::value`
template<typename ClassT, typename...ArgsT> constexpr bool_t is_nothrow_copy_constructible_v = is_nothrow_copy_constructible<ClassT>{};



// fennec::is_move_constructible ---------------------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} is move constructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_move_constructible
	: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_rvalue_reference_t<ClassT>)> {};

///
/// \brief Shorthand for `is_copy_constructible<ClassT>::value`
template<typename ClassT, typename...ArgsT> constexpr bool_t is_move_constructible_v = is_move_constructible<ClassT>{};



// fennec::is_trivially_move_constructible -----------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} is trivially move constructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_trivially_move_constructible
	: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {};

///
/// \brief Shorthand for `is_trivially_move_constructible<ClassT>::value`
	template<typename ClassT, typename...ArgsT> constexpr bool_t is_trivially_move_constructible_v = is_trivially_move_constructible<ClassT>{};



// fennec::is_nothrow_move_constructible -------------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} is nothrow move constructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_nothrow_move_constructible
	: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {};

///
/// \brief Shorthand for `is_nothrow_move_constructible<ClassT>::value`
template<typename ClassT, typename...ArgsT> constexpr bool_t is_nothrow_move_constructible_v = is_nothrow_move_constructible<ClassT>{};



// fennec::is_assignable -----------------------------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} is assignable
/// \tparam ClassAT The class type to test
/// \tparam ClassBT The arguments for the specific constructor
template<typename ClassAT, typename ClassBT> struct is_assignable
	: bool_constant<FENNEC_BUILTIN_IS_ASSIGNABLE(ClassAT, ClassBT)> {};

///
/// \brief Shorthand for `is_constructible<ClassT, ArgsT...>::value`
template<typename ClassAT, typename ClassBT> constexpr bool_t is_assignable_v = is_assignable<ClassAT, ClassBT>{};



// fennec::is_trivially_assignable -------------------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} is trivially assignable
/// \tparam ClassAT The class type to test
/// \tparam ClassBT The arguments for the specific constructor
template<typename ClassAT, typename ClassBT> struct is_trivially_assignable
	: bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_ASSIGNABLE(ClassAT, ClassBT)> {};

///
/// \brief Shorthand for `is_trivially_assignable<ClassT, ArgsT...>::value`
template<typename ClassAT, typename ClassBT> constexpr bool_t is_trivially_assignable_v = is_trivially_assignable<ClassAT, ClassBT>{};




// fennec::is_nothrow_assignable ---------------------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} is nothrow assignable
/// \tparam ClassAT The class type to test
/// \tparam ClassBT The arguments for the specific constructor
template<typename ClassAT, typename ClassBT> struct is_nothrow_assignable
	: bool_constant<FENNEC_BUILTIN_IS_NOTHROW_ASSIGNABLE(ClassAT, ClassBT)> {};

///
/// \brief Shorthand for `is_nothrow_assignable<ClassT, ArgsT...>::value`
template<typename ClassAT, typename ClassBT> constexpr bool_t is_nothrow_assignable_v = is_nothrow_assignable<ClassAT, ClassBT>{};



// fennec::is_copy_assignable ------------------------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} is copy assignable
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_copy_assignable
	: bool_constant<FENNEC_BUILTIN_IS_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_lvalue_reference_t<const ClassT>)> {};

///
/// \brief Shorthand for `is_copy_assignable<ClassT>::value`
template<typename ClassT> constexpr bool_t is_copy_assignable_v = is_copy_assignable<ClassT>{};



// fennec::is_trivially_copy_assignable --------------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} is trivially_copy assignable
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_trivially_copy_assignable
	: bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_lvalue_reference_t<const ClassT>)> {};

///
/// \brief Shorthand for `is_trivially_copy_assignable<ClassT>::value`
template<typename ClassT> constexpr bool_t is_trivially_copy_assignable_v = is_trivially_copy_assignable<ClassT>{};



// fennec::is_nothrow_copy_assignable ----------------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} is nothrow_copy assignable
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_nothrow_copy_assignable
	: bool_constant<FENNEC_BUILTIN_IS_NOTHROW_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_lvalue_reference_t<const ClassT>)> {};

///
/// \brief Shorthand for `is_nothrow_copy_assignable<ClassT>::value`
template<typename ClassT> constexpr bool_t is_nothrow_copy_assignable_v = is_nothrow_copy_assignable<ClassT>{};



// fennec::is_move_assignable ------------------------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} is move assignable
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_move_assignable
	: bool_constant<FENNEC_BUILTIN_IS_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_rvalue_reference_t<ClassT>)> {};

///
/// \brief Shorthand for `is_move_assignable<ClassT>::value`
template<typename ClassT> constexpr bool_t is_move_assignable_v = is_move_assignable<ClassT>{};



// fennec::is_trivially_move_assignable --------------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} is trivially_move assignable
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_trivially_move_assignable
	: bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_rvalue_reference_t<ClassT>)> {};

///
/// \brief Shorthand for `is_trivially_move_assignable<ClassT>::value`
template<typename ClassT> constexpr bool_t is_trivially_move_assignable_v = is_trivially_move_assignable<ClassT>{};



// fennec::is_nothrow_move_assignable --------------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} is nothrow_move assignable
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_nothrow_move_assignable
	: bool_constant<FENNEC_BUILTIN_IS_NOTHROW_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_rvalue_reference_t<ClassT>)> {};

///
/// \brief Shorthand for `is_nothrow_move_assignable<ClassT>::value`
template<typename ClassT> constexpr bool_t is_nothrow_move_assignable_v = is_nothrow_move_assignable<ClassT>{};



// fennec::is_destructible ---------------------------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} is destructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_destructible
	: detail::_is_destructible<ClassT>::type {};

///
/// \brief Shorthand for `is_destructible<ClassT, ArgsT...>::value`
template<typename ClassT> constexpr bool_t is_destructible_v = is_destructible<ClassT>{};



// fennec::is_trivially_destructible -----------------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} is trivially destructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_trivially_destructible
#if FENNEC_HAS_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE
	: bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE(ClassT)> {};
#else
	: bool_constant<FENNEC_BUILTIN_HAS_TRIVIAL_DESTRUCTOR(ClassT)> {};
#endif

///
/// \brief Shorthand for `is_trivially_destructible<ClassT, ArgsT...>::value`
template<typename ClassT> constexpr bool_t is_trivially_destructible_v = is_trivially_destructible<ClassT>{};



// fennec::is_nothrow_destructible -------------------------------------------------------------------------------------

///
/// \brief Check if \emph{ClassT} is nothrow destructible
/// \tparam ClassT The class type to test
template<typename ClassT> struct is_nothrow_destructible
	: detail::_is_nothrow_destructible<ClassT>::type {};

///
/// \brief Shorthand for `is_nothrow_destructible<ClassT, ArgsT...>::value`
template<typename ClassT> constexpr bool_t is_nothrow_destructible_v = is_nothrow_destructible<ClassT>{};





// Type Relationships ==================================================================================================


// fennec::is_same -----------------------------------------------------------------------------------------------------

///
/// \brief Check if the two types are identical
///
/// \details Checks if \emph{T0} and \emph{T1} are identical and store it in `is_same::value`
/// \tparam T0 first type to check
/// \tparam T1 second type to check
template<typename T0, typename T1> struct is_same : false_type {};

// true case
template<typename T> struct is_same<T, T> : true_type {};

///
/// \brief Shorthand for `(.*?)`
/// \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> {};



// fennec::is_base_of --------------------------------------------------------------------------------------------------

///
/// \brief Check if \emph{Derived} has a base type of \emph{Base}
///
/// \details Checks if \emph{Base} is a base type of \emph{Derived} and stores it in `is_base_of::value`
/// \tparam Base base type to check
/// \tparam Derived derived type to check
template<typename Base, typename Derived> struct is_base_of : bool_constant<
	is_class_v<Base> and is_class_v<Derived> and decltype(detail::_is_base_of<Base, Derived>(0))::value
> {};

///
/// \brief Shorthand for `(.*?)`
/// \tparam Base base type to check
/// \tparam Derived derived type to check
template<typename Base, typename Derived> constexpr bool_t is_base_of_v = is_base_of<Base, Derived> {};



// fennec::is_iterable -------------------------------------------------------------------------------------------------

///
/// \brief Check if type \emph{T} is iterable
///
/// \details Checks if \emph{Base} is iterable and stores it in `is_base_of::value`
/// \tparam T type to check
template<typename T> struct is_iterable : decltype(detail::_is_iterable<T>(0)) {};

///
/// \brief Shorthand for `is_iterable<TypeT0, TypeT1>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_iterable_v = is_iterable<T>{};



// fennec::is_iterator -------------------------------------------------------------------------------------------------

///
/// \brief Check if type \emph{T} is an iterator
///
/// \details Checks if \emph{T} is an iterator and stores it in `is_base_of::value`
/// \tparam T type to check
template<typename T> struct is_iterator : decltype(detail::_is_iterator<T>(0)) {};

///
/// \brief Shorthand for `is_iterator<TypeT0, TypeT1>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_iterator_v = is_iterator<T>{};



// fennec::is_indexable ------------------------------------------------------------------------------------------------

///
/// \brief Check if type \emph{T} is indexable
///
/// \details Checks if \emph{T}
/// \tparam T type to check
template<typename T> struct is_indexable : decltype(detail::_is_indexable<T>(0)) {};

///
/// \brief Shorthand for `is_indexable<TypeT0, TypeT1>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_indexable_v = is_indexable<T>{};



// fennec::is_mappable -------------------------------------------------------------------------------------------------

///
/// \brief Check if type \emph{T} is mappable
///
/// \details Checks if \emph{T}
/// \tparam T type to check
template<typename T> struct is_mappable : decltype(detail::_is_mappable<T>(0)) {};

///
/// \brief Shorthand for `is_mappable<TypeT0, TypeT1>::value`
/// \tparam T type to check
template<typename T> constexpr bool_t is_mappable_v = is_mappable<T>{};


}

#endif // FENNEC_LANG_TYPE_TRAITS_H
