// =====================================================================================================================
//  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 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 License for more details.
//
//  You should have received a copy of the GNU General License
//  along with this program.  If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================

///
/// \file type_transforms.h
/// \brief \ref fennec_lang_type_transforms
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///

#ifndef FENNEC_LANG_TYPE_TRANSFORMS_H
#define FENNEC_LANG_TYPE_TRANSFORMS_H

#include <fennec/lang/type_identity.h>
#include <fennec/lang/detail/_type_transforms.h>

///
/// \page fennec_lang_type_transforms Type Transforms
///
/// \brief Part of the fennec metaprogramming library. This header defines structures for copying types with different traits
///        or rather, transform them, at compile time.
///
/// \code #include <fennec/lang/type_transforms.h> \endcode
///
///
/// <table width="100%" class="fieldtable" id="table_fennec_lang_type_transforms">
/// <tr><th style="vertical-align: top">Syntax
///     <th style="vertical-align: top">Description
/// <tr><td width="50%" style="vertical-align: top"> <br>
///         \ref fennec::add_pointer "add_pointer<TypeT>::type"<br>
///         \ref fennec::add_pointer_t "add_pointer_t<TypeT>"
///     <td width="50%" style="vertical-align: top">
///         \copydetails fennec::add_pointer
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///         \ref fennec::remove_pointer "remove_pointer<TypeT>::type"<br>
///         \ref fennec::remove_pointer_t "remove_pointer_t<TypeT>"
///     <td width="50%" style="vertical-align: top">
///         \copydetails fennec::remove_pointer
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///         \ref fennec::add_reference "add_reference<TypeT>::type"<br>
///         \ref fennec::add_reference_t "add_reference_t<TypeT>"
///     <td width="50%" style="vertical-align: top">
///         \copydetails fennec::add_reference
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///         \ref fennec::remove_reference "remove_reference<TypeT>::type"<br>
///         \ref fennec::remove_reference_t "remove_reference_t<TypeT>"
///     <td width="50%" style="vertical-align: top">
///         \copydetails fennec::remove_reference
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///         \ref fennec::add_const "add_const<TypeT>::type"<br>
///         \ref fennec::add_const_t "add_const_t<TypeT>"
///     <td width="50%" style="vertical-align: top">
///         \copydetails fennec::add_const
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///         \ref fennec::remove_const "remove_const<TypeT>::type"<br>
///         \ref fennec::remove_const_t "remove_const_t<TypeT>"
///     <td width="50%" style="vertical-align: top">
///         \copydetails fennec::remove_const
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///         \ref fennec::add_volatile "add_volatile<TypeT>::type"<br>
///         \ref fennec::add_volatile_t "add_volatile_t<TypeT>"
///     <td width="50%" style="vertical-align: top">
///         \copydetails fennec::add_volatile
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///         \ref fennec::remove_volatile "remove_volatile<TypeT>::type"<br>
///         \ref fennec::remove_volatile_t "remove_volatile_t<TypeT>"
///     <td width="50%" style="vertical-align: top">
///         \copydetails fennec::remove_volatile
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///         \ref fennec::add_cv "add_cv<TypeT>::type"<br>
///         \ref fennec::add_cv_t "add_cv_t<TypeT>"
///     <td width="50%" style="vertical-align: top">
///         \copydetails fennec::add_cv
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///         \ref fennec::remove_cv "remove_cv<TypeT>::type"<br>
///         \ref fennec::remove_cv_t "remove_cv_t<TypeT>"
///     <td width="50%" style="vertical-align: top">
///         \copydetails fennec::remove_cv
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///         \ref fennec::add_cvr "add_cvr<TypeT>::type"<br>
///         \ref fennec::add_cvr_t "add_cvr_t<TypeT>"
///     <td width="50%" style="vertical-align: top">
///         \copydetails fennec::add_cvr
///
/// <tr><td width="50%" style="vertical-align: top"> <br>
///         \ref fennec::remove_cvr "remove_cvr<TypeT>::type"<br>
///         \ref fennec::remove_cvr_t "remove_cvr_t<TypeT>"
///     <td width="50%" style="vertical-align: top">
///         \copydetails fennec::remove_cvr
///
/// </table>
///


namespace fennec
{

// Pointer Conversions =================================================================================================

///
/// \brief adds a pointer level to \p T
///
/// \details adds a pointer to the provided type such that `T` becomes `T*`
/// \tparam T Resultant Type
template<typename T> struct add_pointer : type_identity<T*>{};

///
/// \brief shorthand for `typename add_pointer<T>::type`
template<typename T> using add_pointer_t = typename add_pointer<T>::type;


///
/// \brief removes a pointer level from \p T
///
/// \details removes a pointer from the provided type such that `T*` becomes `T`
/// \tparam T Resultant Type
template<typename T> struct remove_pointer : type_identity<T> {};

// specialization for T*
template<typename T> struct remove_pointer<T*> : type_identity<T> {};

///
/// \brief shorthand for `typename remove_pointer<T>::type`
template<typename T> using remove_pointer_t = typename remove_pointer<T>::type;



// Reference Conversions ===============================================================================================

///
/// \brief add a reference to \p T
///
/// \details adds a pointer to the provided type such that `T` becomes `T&`
/// \tparam T Resultant Type
template<typename T> struct add_reference : type_identity<T&> {};

///
/// \brief shorthand for `typename add_reference<T>::type`
template<typename T> using  add_reference_t = typename add_reference<T>::type;


///
/// \brief remove a reference from \p T
///
/// \details removes references from the provided type such that `T&` and `T&&` become `T`
/// \tparam T Reference Type
template<typename T> struct remove_reference : type_identity<T> {};

// specialization for `T&`
template<typename T> struct remove_reference<T&> : type_identity<T> {};

// specialization for `T&&`
template<typename T> struct remove_reference<T&&> : type_identity<T> {};

///
/// \brief shorthand for `typename remove_reference<T>::type`
template<typename T> using  remove_reference_t = typename remove_reference<T>::type;


///
/// \brief add a lvalue reference to \p T
///
/// \details adds a lvalue reference to the provided type such that 'T' becomes 'T&'
/// \tparam T Reference Type
template<typename T> struct add_lvalue_reference : detail::_add_lvalue_reference<T> {};

///
/// \brief shorthand for `typename remove_reference<T>::type`
template<typename T> using  add_lvalue_reference_t = typename add_lvalue_reference<T>::type;


///
/// \brief add a rvalue reference to \p T
///
/// \details adds a rvalue reference to the provided type such that 'T' becomes 'T&&'
/// \tparam T Reference Type
template<typename T> struct add_rvalue_reference : detail::_add_rvalue_reference<T> {};

///
/// \brief shorthand for `typename remove_reference<T>::type`
template<typename T> using  add_rvalue_reference_t = typename add_rvalue_reference<T>::type;



// Const & Volatile Conversions ========================================================================================

///
/// \brief add the const qualifier to the provided type \p T
///
/// \details adds const qualification to the provided type such that `T` becomes `const T`
/// \tparam T Reference Type
template<typename T> struct add_const : type_identity<const T> {};

///
/// \brief shorthand for `typename add_const<T>::type`
template<typename T> using add_const_t = typename add_const<T>::type;

// specialization for const types
template<typename T> struct add_const<const T> : type_identity<const T> {};


///
/// \brief remove the const qualifier from the provided type \p T
///
/// \details removes const qualification from the provided type such that `const T` becomes `T`
/// \tparam T Reference Type
template<typename T> struct remove_const : type_identity<T> {};

///
/// \brief shorthand for `typename remove_const<T>::type`
template<typename T> using remove_const_t = typename remove_const<T>::type;

// specialization for const types
template<typename T> struct remove_const<const T> : type_identity<T> {};



///
/// \brief add the volatile qualifier to the provided type \p T
///
/// \details removes references from the provided type such that `T` becomes `volatile T`
/// \tparam T Reference Type
template<typename T> struct add_volatile : type_identity<volatile T> {};

///
/// \brief shorthand for `typename add_volatile<T>::type`
template<typename T> using add_volatile_t = typename add_volatile<T>::type;

// specialization for volatile types
template<typename T> struct add_volatile<volatile T> : type_identity<volatile T> {};


///
/// \brief remove the volatile qualifier from the provided type \p T
///
/// \details removes references from the provided type such that `volatile T` becomes `T`
/// \tparam T Reference Type
template<typename T> struct remove_volatile : type_identity<T> {};

///
/// \brief shorthand for `typename remove_volatile<T>::type`
template<typename T> using remove_volatile_t = typename remove_volatile<T>::type;

// specialization for volatile types
template<typename T> struct remove_volatile<volatile T> : type_identity<T> {};



///
/// \brief remove the volatile qualifier from the provided type \p T
///
/// \details removes references from the provided type such that `T`, `const T`, and `volatile T` become
///          `const volatile T`
/// \tparam T Reference Type
template<typename T> struct add_cv : type_identity<const volatile T> {};

///
/// \brief shorthand for `typename add_cv<T>::type`
template<typename T> using add_cv_t = typename add_cv<T>::type;

// specialization for const types
template<typename T> struct add_cv<const T> : type_identity<const volatile T> {};

// specialization for volatile types
template<typename T> struct add_cv<volatile T> : type_identity<const volatile T> {};

// specialization for const volatile types
template<typename T> struct add_cv<const volatile T> : type_identity<const volatile T> {};



///
/// \brief remove the const and volatile qualifiers from the provided type \p T
///
/// \details removes const and volatile from the provided type such that `const T`, `volatile T`, and
///          `const volatile T` become `T`
/// \tparam T Reference Type
template<typename T> struct remove_cv : type_identity<T> {};

// specialization for const types
template<typename T> struct remove_cv<const T> : type_identity<T> {};

// specialization for volatile types
template<typename T> struct remove_cv<volatile T> : type_identity<T> {};

// specialization for const volatile types
template<typename T> struct remove_cv<const volatile T> : type_identity<T> {};

///
/// \brief shorthand for `typename remove_cv<T>::type`
template<typename T> using remove_cv_t = typename remove_cv<T>::type;



///
/// \brief add a reference and the const volatile qualifiers from the provided type \p T
///
/// \details adds references and const volatile qualifiers to the provided type.
/// \tparam T Reference Type
template<typename T> struct add_cvr : type_identity<add_reference_t<add_cv_t<T>>> {};

///
/// \brief shorthand for `typename add_cvr<T>::type`
template<typename T> using add_cvr_t = typename add_cvr<T>::type;



///
/// \brief removes references as well as the const and volatile qualifiers from the provided type \p T
///
/// \details removes const and volatile from the provided type such that
/// \tparam T Reference Type
template<typename T> struct remove_cvr : type_identity<remove_cv_t<remove_reference_t<T>>> {};


///
/// \brief shorthand for `typename remove_cvr<T>::type`
template<typename T> using remove_cvr_t = typename remove_cvr<T>::type;

}

#endif // FENNEC_LANG_TYPE_TRANSFORMS_H
