// -*- C++ -*-
// -----------------------------------------------------------------------------------------------------
// Copyright (c) 2006-2020, Knut Reinert & Freie Universität Berlin
// Copyright (c) 2016-2020, Knut Reinert & MPI für molekulare Genetik
// This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
// shipped with this file and also available at: https://github.com/seqan/seqan3/blob/master/LICENSE.md
// -----------------------------------------------------------------------------------------------------

/*!\file
 * \brief Provides C++20 additions to the type_traits header.
 * \author Hannes Hauswedell <hannes.hauswedell AT fu-berlin.de>
 */

#pragma once

#include <type_traits>

//!\brief A workaround for __cpp_lib_remove_cvref for gcc version >=9.0 and <9.4 (in C++17 mode).
//!       Those versions implemented std::remove_cvref_t, but did not define that feature detection macro.
#ifndef SEQAN3_WORKAROUND_CPP_LIB_REMOVE_CVREF
#   if defined(__cpp_lib_remove_cvref)
#       define SEQAN3_WORKAROUND_CPP_LIB_REMOVE_CVREF 1
#   elif defined(__GNUC__) && ((__GNUC__ == 9) && (__GNUC_MINOR__ < 4)) && __cplusplus > 201703L
#       define SEQAN3_WORKAROUND_CPP_LIB_REMOVE_CVREF 1
#   else
#       define SEQAN3_WORKAROUND_CPP_LIB_REMOVE_CVREF 0
#   endif
#endif

namespace std
{

// ----------------------------------------------------------------------------
// remove_cvref_t
// ----------------------------------------------------------------------------
#if !SEQAN3_WORKAROUND_CPP_LIB_REMOVE_CVREF
/*!\brief Return the input type with `const`, `volatile` and references removed.
 * \tparam t The type to operate on.
 */
template <typename t>
struct remove_cvref;

//!\cond
template <typename t>
    requires true
struct remove_cvref<t> // needed for gcc-9, it defines std::remove_cvref but does not populate __cpp_lib_remove_cvref
{
    using type = std::remove_cv_t<std::remove_reference_t<t>>;
};
//!\endcond

/*!\brief Return the input type with `const`, `volatile` and references removed (transformation_trait shortcut).
 * \tparam t The type to operate on.
 */
template <typename t>
using remove_cvref_t = typename remove_cvref<t>::type;
#endif // !SEQAN3_WORKAROUND_CPP_LIB_REMOVE_CVREF

// ----------------------------------------------------------------------------
// type_identity
// ----------------------------------------------------------------------------
#ifndef __cpp_lib_type_identity
/*!\defgroup std_type_traits type_traits
 * \ingroup std
 * \brief The \<concepts\> header from C++20's standard library.
 */

/*!\brief The identity transformation (a transformation_trait that returns the input).
 * \see https://en.cppreference.com/w/cpp/types/type_identity
 * \ingroup std_type_traits
 */
template <typename t>
struct type_identity;

//!\cond
template <typename t>
    requires true
struct type_identity<t>
{
    //!\brief The return type (which is the argument).
    using type = t;
};
//!\endcond

//!\brief A shortcut for std::type_identity.
//!\ingroup std_type_traits
template <typename t>
using type_identity_t = typename type_identity<t>::type;
#endif // __cpp_lib_type_identity

} // namespace std
