// bslmf_decay.h                                                      -*-C++-*-
#ifndef INCLUDED_BSLMF_DECAY
#define INCLUDED_BSLMF_DECAY

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Convert a type to the type used for pass-by-value.
//
//@CLASSES:
//  bsl::decay: type trait computing return type for type parameter
//  bsl::decay_t: alias to the return type of the 'bsl::decay' meta-function
//
//@SEE_ALSO: bslmf_removeextent
//
//@DESCRIPTION: This component provides a metafunction, 'bsl::decay', that
// applies array-to-pointer and function-to-pointer conversion and
// cv-qualification removal to a type, thus modeling the decay of an argument
// type when passed by-value into a function.  'bsl::decay' provides identical
// functionality to the C++11 standard metafunction 'std::decay'.  From the
// C++14, standard description of 'std::decay':
//
// Let 'U' be 'remove_reference_t<T>'.  If 'is_array<U>::value' is 'true', the
// member typedef 'type' shall equal 'remove_extent_t<U>*'.  If
// 'is_function<U>::value' is 'true', the member typedef 'type' shall equal
// 'add_pointer_t<U>'.  Otherwise the member typedef 'type' equals
// 'remove_cv_t<U>'.  [ *Note*: This behavior is similar to the
// lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer
// (4.3) conversions applied when an lvalue expression is used as an rvalue,
// but also strips cv-qualifiers from class types in order to more closely
// model by-value argument passing.  - *end note* ]
//
///Usage
///-----
//
/// Usage Example 1
/// - - - - - - - -
// A class template needs to cache a value of type 'T'. There is nothing in the
// definition of the class that would prevent it from working for 'T' of
// function type or array-of-unknown bound, but one cannot simply declare a
// member of either of those types.  Instead, we use 'bsl::decay<T>::type',
// which can be stored, copied, and compared as needed:
//..
//  #ifndef INCLUDED_BSLMF_DECAY
//  #include <bslmf_decay.h>
//  #endif
//
//  template <class t_TYPE>
//  class Thing {
//    public:
//
//#ifdef BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES
//..
// Note that if the current compiler supports alias templates C++11 feature, we
// can use 'bsl::decay_t' alias to the "result" type of the 'bsl::decay'
// meta-function, that avoids the '::type' suffix and 'typename' prefix in the
// declaration of the function return type:
//..
//      using CacheType = bsl::decay_t<t_TYPE>;
//#else
//      typedef typename bsl::decay<t_TYPE>::type CacheType;
//#endif
//
//  private:
//      CacheType d_cache;
//      // ...
//
//  public:
//      CacheType cache() const { return d_cache; }
//  };
//..
// Now verify that for function and array types, 'cache()' will return a simple
// pointer:
//..
//  int main()
//  {
//      typedef const int A1[];
//      typedef double A2[3][4];
//      typedef void F1(int);
//      typedef int (&F2)();
//
//      assert((bsl::is_same<const int*,    Thing<A1>::CacheType>::value));
//      assert((bsl::is_same<double(*)[4],  Thing<A2>::CacheType>::value));
//      assert((bsl::is_same<void (*)(int), Thing<F1>::CacheType>::value));
//      assert((bsl::is_same<int (*)(),     Thing<F2>::CacheType>::value));
//
//      return 0;
//  }
//..

#include <bslscm_version.h>

#include <bslmf_assert.h>
#include <bslmf_isarray.h>
#include <bslmf_isfunction.h>
#include <bslmf_removecv.h>
#include <bslmf_removeextent.h>
#include <bslmf_removereference.h>

#include <bsls_compilerfeatures.h>

namespace bsl {

// Forward declaration
template <class t_TYPE, bool t_IS_ARRAY, bool t_IS_FUNC> struct decay_imp;

                        // ====================
                        // class template decay
                        // ====================

template <class t_TYPE>
class decay {
    // Metafunction to return the variant of the specified parameter 't_TYPE'
    // used for pass-by-reference, e.g., by applying array-to-pointer and
    // function-to-pointer conversion.

    typedef typename bsl::remove_reference<t_TYPE>::type U;
    enum {
        k_ISARRAY = is_array<U>::value,
        k_ISFUNC  = is_function<U>::value
    };

  public:
    typedef typename decay_imp<U, k_ISARRAY, k_ISFUNC>::type type;
};

#ifdef BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES

// ALIASES
template <class t_TYPE>
using decay_t = typename decay<t_TYPE>::type;
    // 'decay_t' is an alias to the return type of the 'bsl::decay'
    // meta-function.  Note, that the 'enable_if_t' avoids the '::type' suffix
    // and 'typename' prefix when we want to use the result of the
    // meta-function in templates.

#endif  // BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES

// ============================================================================
//                      CLASS TEMPLATE IMPLEMENTATION
// ============================================================================

template <class t_TYPE, bool t_IS_ARRAY, bool t_IS_FUNC>
struct decay_imp : remove_cv<t_TYPE> {
    BSLMF_ASSERT(!(t_IS_ARRAY || t_IS_FUNC));
};

template <class t_TYPE>
struct decay_imp<t_TYPE, true /* t_IS_ARRAY */, false /* t_IS_FUNC */> {
    typedef typename remove_extent<t_TYPE>::type *type;
};

template <class t_TYPE>
struct decay_imp<t_TYPE, false /* t_IS_ARRAY */, true /* t_IS_FUNC */> {
    typedef t_TYPE *type;
};

}  // close namespace bsl

#endif // ! defined(INCLUDED_BSLMF_DECAY)

// ----------------------------------------------------------------------------
// Copyright 2016 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------