// bslmf_integralconstant.h                                           -*-C++-*-
#ifndef INCLUDED_BSLMF_INTEGRALCONSTANT
#define INCLUDED_BSLMF_INTEGRALCONSTANT

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

//@PURPOSE: Provide a mapping from integral constants to unique types.
//
//@CLASSES:
// bsl::integral_constant: A type representing a specific integer value
//        bsl::false_type: 'typedef' for 'integral_constant<bool, false>'
//         bsl::true_type: 'typedef' for 'integral_constant<bool, true>'
//
//@SEE_ALSO:
//
//@DESCRIPTION: This component describes a simple class template,
// 'bsl::integral_constant', that is used to map an integer constant to a C++
// type.  'integral_constant<t_TYPE, t_VAL>' generates a unique type for each
// distinct compile-time integral 't_TYPE' and constant integer 't_VAL'
// parameter.  That is, instantiations with different integer types and values
// form distinct types, so that 'integral_constant<int, 0>' is a different type
// from 'integral_constant<int, 1>', which is also distinct from
// 'integral_constant<unsigned, 1>', and so on.  This mapping of integer values
// to types allows for "overloading by value", i.e., multiple functions with
// the same name can be overloaded on the "value" of an 'integral_constant'
// argument, provided that the value is known at compile-time.  The typedefs
// 'bsl::true_type' and 'bsl::false_type' map the predicate values 'true' and
// 'false' to C++ types that are frequently useful for compile-time algorithms.
//
///Usage
///-----
// This section illustrates intended usage of this component
//
///Example 1: Compile-Time Function Dispatching
/// - - - - - - - - - - - - - - - - - - - - - -
// The most common use of this structure is to perform compile-time function
// dispatching based on a compile-time calculation.  Often the calculation is
// nothing more than a simple predicate, allowing us to select one of two
// functions based on whether the predicate holds.  The following function,
// 'doSomething', uses a fast implementation (e.g., using 'memcpy') if the
// parameterized type allows for such operations, otherwise it will use a more
// generic and slower implementation (e.g., using the copy constructor).  This
// example uses the types 'true_type' and 'false_type', which are simple
// typedefs for 'integral_constant<bool, true>' and
// 'integral_constant<bool, false>', respectively.
//..
//    #include <bslmf_integralconstant.h>
//
//    template <class t_T>
//    int doSomethingImp(t_T *t, bsl::true_type)
//    {
//        // slow, generic implementation
//        // ...
//        (void) t;
//        return 11;
//    }
//
//    template <class t_T>
//    int doSomethingImp(t_T *t, bsl::false_type)
//    {
//        // fast implementation that works only for some types of 't_T'
//        // ...
//        (void) t;
//        return 55;
//    }
//
//    template <bool IsSlow, class t_T>
//    int doSomething(t_T *t)
//    {
//        // Dispatch to an implementation depending on the (compile-time)
//        // value of 'IsSlow'.
//        return doSomethingImp(t, bsl::integral_constant<bool, IsSlow>());
//    }
//..
// For some parameter types, the fast version of 'doSomethingImp' is not
// legal.  The power of this approach is that the compiler will not attempt
// semantic analysis on the implementation that does not match the appropriate
// 'integral_constant' argument.
//..
//    int main()
//    {
//        int r;
//
//        int i;
//        r = doSomething<false>(&i);   // select fast version for int
//        assert(55 == r);
//
//        double m;
//        r = doSomething<true>(&m); // select slow version for double
//        assert(11 == r);
//
//        return 0;
//    }
//..
//
///Example 2: Base Class For Metafunctions
///- - - - - - - - - - - - - - - - - - - -
// Hard-coding the value of an 'integral_constant' is not especially useful.
// Rather, 'integral_constant' is typically used as the base class for
// "metafunction" classes, classes that yield the value of compile-time
// properties, including properties that are associated with types, rather
// than with values.  For example, the following metafunction can be used at
// compile time to determine whether a type is a floating point type:
//..
//    template <class t_TYPE> struct IsFloatingPoint  : bsl::false_type { };
//    template <> struct IsFloatingPoint<float>       : bsl::true_type { };
//    template <> struct IsFloatingPoint<double>      : bsl::true_type { };
//    template <> struct IsFloatingPoint<long double> : bsl::true_type { };
//..
// The value 'IsFloatingPoint<int>::value' is false and
// 'IsFloatingPoint<double>::value' is true.  The 'integral_constant' base
// class has a member type, 'type', that refers to itself and is inherited by
// 'IsFloatingPoint'.  Thus 'IsFloatingPoint<float>::type' is 'true_type' and
// 'IsFloatingPoint<char>::type' is 'false_type'.  'IsFloatingPoint' is an a
// member of a common category of metafunctions known as "type traits" because
// they express certain properties (traits) of a type.  Using this
// metafunction, we can rewrite the 'doSomething' function from first example
// so that it does not require the user to specify the 'IsSlow' template
// argument:
//..
//    template <class t_T>
//    int doSomething2(t_T *t)
//    {
//        // Automatically detect whether to use slow or fast imp.
//        const bool isSlow = IsFloatingPoint<t_T>::value;
//        return doSomethingImp(t, bsl::integral_constant<bool, isSlow>());
//    }
//
//    int main()
//    {
//        int r;
//
//        int i;
//        r = doSomething2(&i); // select fast version for int
//        assert(55 == r);
//
//        double m;
//        r = doSomething2(&m); // select slow version for double
//        assert(11 == r);
//
//        return 0;
//    }
//..

#include <bslscm_version.h>

#include <bsls_compilerfeatures.h>
#include <bsls_keyword.h>
#include <bsls_libraryfeatures.h>

#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
# include <type_traits>
#endif // BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER

#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
#include <bsls_nativestd.h>
#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES

namespace BloombergLP {
namespace bslmf {
template <int> struct MetaInt;
}  // close package namespace
}  // close enterprise namespace

namespace bsl {

                        // ================================
                        // class template integral_constant
                        // ================================

#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
template <class t_TYPE, t_TYPE t_VAL>
struct integral_constant : ::std::integral_constant<t_TYPE, t_VAL> {
    typedef integral_constant type;
};

template <>
struct integral_constant<bool, false> : ::std::false_type
{
    typedef integral_constant type;

    // COMPATIBILITY MEMBERS
    typedef BloombergLP::bslmf::MetaInt<false> Type;
    static BSLS_KEYWORD_CONSTEXPR_MEMBER bool VALUE = false;
};

template <>
struct integral_constant<bool, true> : ::std::true_type
{
    typedef integral_constant type;

    // COMPATIBILITY MEMBERS
    typedef BloombergLP::bslmf::MetaInt<true> Type;
    static BSLS_KEYWORD_CONSTEXPR_MEMBER bool VALUE = true;
};

#else
template <class t_TYPE, t_TYPE t_VAL>
struct integral_constant {
    // Generate a unique type for the given 't_TYPE' and 't_VAL'.  This
    // 'struct' is used for compile-time dispatch of overloaded functions and
    // as the base class for many metafunctions.

  public:
    // CREATORS
    //! integral_constant() = default;
    //! integral_constant(const integral_constant&) = default;
    //! integral_constant operator=(const integral_constant&) = default;
    //! ~integral_constant() = default;

    // PUBLIC TYPES
    typedef t_TYPE            value_type;
    typedef integral_constant type;

    // PUBLIC CLASS DATA
    static BSLS_KEYWORD_CONSTEXPR_MEMBER t_TYPE value = t_VAL;

    // ACCESSORS
    BSLS_KEYWORD_CONSTEXPR operator value_type() const BSLS_KEYWORD_NOEXCEPT;
        // Return 't_VAL'.
};

template <bool t_VAL>
struct integral_constant<bool, t_VAL> {
  public:
    // CREATORS
    //! integral_constant() = default;
    //! integral_constant(const integral_constant&) = default;
    //! integral_constant operator=(const integral_constant&) = default;
    //! ~integral_constant() = default;

    // PUBLIC TYPES
    typedef bool              value_type;
    typedef integral_constant type;

    // PUBLIC CLASS DATA
    static BSLS_KEYWORD_CONSTEXPR_MEMBER bool value = t_VAL;

    // ACCESSORS
    BSLS_KEYWORD_CONSTEXPR operator value_type() const BSLS_KEYWORD_NOEXCEPT;
        // Return 't_VAL'.

    // COMPATIBILITY MEMBERS
    typedef BloombergLP::bslmf::MetaInt<t_VAL> Type;
    static BSLS_KEYWORD_CONSTEXPR_MEMBER bool  VALUE = t_VAL;
};
#endif //   defined(BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER)

                        // ===============
                        // type false_type
                        // ===============

typedef integral_constant<bool, false> false_type;

                        // ===============
                        // type true_type
                        // ===============

typedef integral_constant<bool, true> true_type;

                        // ======================
                        // template bool_constant
                        // ======================

#ifdef BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES
template <bool t_VALUE>
using bool_constant = integral_constant<bool, t_VALUE>;

# if !defined(BSLS_LIBRARYFEATURES_HAS_CPP17_BOOL_CONSTANT)
#   define BSLS_LIBRARYFEATURES_HAS_CPP17_BOOL_CONSTANT          1
# endif
#endif

}  // close namespace bsl

// ============================================================================
//                      INLINE FUNCTION DEFINITIONS
// ============================================================================
// STATIC MEMBER VARIABLE DEFINITIONS
// Note that these definitions are deprecated under C++17, when 'constexpr'
// data members are implicitly 'inline'.
#if !defined(BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER)
// This variable will be supplied by the platform header, when available.
template <class t_TYPE, t_TYPE t_VAL>
BSLS_KEYWORD_CONSTEXPR_MEMBER t_TYPE
    bsl::integral_constant<t_TYPE, t_VAL>::value;

template <bool t_VAL>
BSLS_KEYWORD_CONSTEXPR_MEMBER bool bsl::integral_constant<bool, t_VAL>::value;
template <bool t_VAL>
BSLS_KEYWORD_CONSTEXPR_MEMBER bool bsl::integral_constant<bool, t_VAL>::VALUE;

// ACCESSORS
template <class t_TYPE, t_TYPE t_VAL>
inline
BSLS_KEYWORD_CONSTEXPR bsl::integral_constant<t_TYPE, t_VAL>::operator t_TYPE()
    const BSLS_KEYWORD_NOEXCEPT
{
    return t_VAL;
}

template <bool t_VAL>
inline
BSLS_KEYWORD_CONSTEXPR bsl::integral_constant<bool, t_VAL>::operator bool()
    const BSLS_KEYWORD_NOEXCEPT
{
    return t_VAL;
}
#endif // ! defined(BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER)

#endif // ! defined(INCLUDED_BSLMF_INTEGRALCONSTANT)

// ----------------------------------------------------------------------------
// Copyright 2013 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 ----------------------------------