// bslmf_metaint.h                                                    -*-C++-*-
#ifndef INCLUDED_BSLMF_METAINT
#define INCLUDED_BSLMF_METAINT

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

//@PURPOSE: Provide a meta-function to map integral constants to unique types.
//
//@DEPRECATED: Use 'bslmf_integralconstant' instead.
//
//@CLASSES:
//  bslmf::MetaInt: meta-function mapping integral constants to C++ types
//
//@DESCRIPTION: This component defines a simple template structure used to map
// an integral constant to a C++ type.  'bslmf::MetaInt<int>' defines a
// different type for each distinct compile-time constant integral parameter.
// That is, instantiations with different integer values form distinct types,
// so that 'bslmf::MetaInt<0>' is a distinct type from 'bslmf::MetaInt<1>',
// which is also distinct from 'bslmf::MetaInt<2>', and so on.
//
///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 static 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.  The following function, 'doSomething', uses a fast
// implementation (e.g., 'memcpy') if the parameterized type allows for such
// operations, otherwise it will use a more generic and slower implementation
// (e.g., copy constructor).
//..
//  template <class T>
//  void doSomethingImp(T *t, bslmf::MetaInt<0>)
//  {
//      // slow generic implementation
//      (void) t;
//      // ...
//  }
//
//  template <class T>
//  void doSomethingImp(T *t, bslmf::MetaInt<1>)
//  {
//      // fast implementation (works only for some T's)
//      (void) t;
//      // ...
//  }
//
//  template <class T, bool IsFast>
//  void doSomething(T *t)
//  {
//      doSomethingImp(t, bslmf::MetaInt<IsFast>());
//  }
//..
// The power of this approach is that the compiler will compile only the
// implementation selected by the 'MetaInt' argument.  For some parameter
// types, the fast version of 'doSomethingImp' would be ill-formed.  This kind
// of compile-time dispatch prevents the ill-formed version from ever being
// instantiated.
//..
//  int main()
//  {
//      int i;
//      doSomething<int, true>(&i); // fast version selected for int
//
//      double m;
//      doSomething<double, false>(&m); // slow version selected for double
//
//      return 0;
//  }
//..
//
///Example 2: Reading the 'VALUE' Member
///- - - - - - - - - - - - - - - - - - -
// In addition to forming new types, the value of the integral parameter to
// 'MetaInt' is "saved" in the enum member 'VALUE', and is accessible for use
// in compile-time or run-time operations.
//..
//  template <int V>
//  unsigned g()
//  {
//      bslmf::MetaInt<V> i;
//      assert(V == i.VALUE);
//      assert(V == bslmf::MetaInt<V>::VALUE);
//      return bslmf::MetaInt<V>::VALUE;
//  }
//
//  int main()
//  {
//      int v = g<1>();
//      assert(1 == v);
//      return 0;
//  }
//..

#include <bslscm_version.h>

#include <bslmf_integralconstant.h>
#include <bslmf_tag.h>

#include <bsls_compilerfeatures.h>

namespace BloombergLP {

namespace bslmf {

                           // ==============
                           // struct MetaInt
                           // ==============

template <int t_INT_VALUE>
struct MetaInt : public bsl::integral_constant<int, t_INT_VALUE> {
    // Instantiating this template produces a distinct type for each
    // non-negative integer value.  This template has been deprecated in favor
    // of the standard 'integral_constant' template.

#if defined(BSLS_COMPILERFEATURES_SUPPORT_STATIC_ASSERT)
    static_assert(t_INT_VALUE >= 0, "t_INT_VALUE must be non-negative");
#endif

    // TYPES
    typedef MetaInt<t_INT_VALUE>    Type;
    typedef bslmf::Tag<t_INT_VALUE> Tag;

    enum { VALUE = t_INT_VALUE };

    // CREATORS
    MetaInt();
        // Does nothing ('MetaInt' is stateless).

    MetaInt(bsl::integral_constant<int, t_INT_VALUE>);              // IMPLICIT
        // Convert from a 'bsl::integral_constant<int, t_INT_VALUE>'.

    //! MetaInt(const MetaInt&) = default;
    //! MetaInt& operator=(const MetaInt&) = default;
    //! ~MetaInt() = default;

    // CLASS METHODS
    static Tag& tag();
        // Declared but not defined.  Meta-function use only.  The tag can be
        // used to recover meta-information from an expression.  Example:
        // 'sizeof(f(expr).tag())' returns a different compile-time value
        // depending on the type of the result of calling the 'f' function but
        // does not actually call the 'f' function or the 'tag' method at
        // run-time.  Note that 'f(expr)::VALUE' or 'sizeof(f(expr)::Type)'
        // would be ill-formed and that 'f(expr).value' is not a compile-time
        // expression.
};

template <>
struct MetaInt<0> : public bsl::false_type {
    // This specialization of 'MetaInt' has a 'VAL' of zero and is convertible
    // to and from 'bsl::false_type'.

    // TYPES
    typedef MetaInt<0>    Type;
    typedef bslmf::Tag<0> Tag;

    enum { VALUE = 0 };

    // CREATORS
    MetaInt();
        // Does nothing ('MetaInt' is stateless).

    MetaInt(bsl::false_type);                                       // IMPLICIT
        // Convert from a 'bsl::false_type'.

    //! MetaInt(const MetaInt&) = default;
    //! MetaInt& operator=(const MetaInt&) = default;
    //! ~MetaInt() = default;

    // CLASS METHODS
    static Tag& tag();
        // Declared but not defined.  Meta-function use only.  The tag can be
        // used to recover meta-information from an expression.  Example:
        // 'sizeof(f(expr).tag())' returns a different compile-time value
        // depending on the type of the result of calling the 'f' function but
        // does not actually call the 'f' function or the 'tag' method at
        // run-time.  Note that 'f(expr)::VALUE' or 'sizeof(f(expr)::Type)'
        // would be ill-formed and that 'f(expr).value' is not a compile-time
        // expression.

    // ACCESSORS
    operator bool() const;
        // Return 'false'.  (This operator is conversion operator to 'bool'.)
};

template <>
struct MetaInt<1> : public bsl::true_type {
    // This specialization of 'MetaInt' has a 'VAL' of one and is convertible
    // to and from 'bsl::true_type'.

    // TYPES
    typedef MetaInt<1>    Type;
    typedef bslmf::Tag<1> Tag;

    enum { VALUE = 1 };

    // CREATORS
    MetaInt();
        // Does nothing ('MetaInt' is stateless).

    MetaInt(bsl::true_type);                                        // IMPLICIT
        // Convert from a 'bsl::true_type'.

    //! MetaInt(const MetaInt&) = default;
    //! MetaInt& operator=(const MetaInt&) = default;
    //! ~MetaInt() = default;

    // CLASS METHODS
    static Tag& tag();
        // Declared but not defined.  Meta-function use only.  The tag can be
        // used to recover meta-information from an expression.  Example:
        // 'sizeof(f(expr).tag())' returns a different compile-time value
        // depending on the type of the result of calling the 'f' function but
        // does not actually call the 'f' function or the 'tag' method at
        // run-time.  Note that 'f(expr)::VALUE' or 'sizeof(f(expr)::Type)'
        // would be ill-formed and that 'f(expr).value' is not a compile-time
        // expression.

    // ACCESSORS
    operator bool() const;
        // Return 'true'.  (This operator is conversion operator to 'bool'.)
};

#define BSLMF_METAINT_TO_INT(expr)  BSLMF_TAG_TO_INT((expr).tag())
    // Given an integral value, 'V', and an expression, 'expr', of type
    // 'bslmf::MetaInt<V>', this macro returns a compile-time constant with
    // value, 'V'.  The expression, 'expr', is not evaluated at run-time.

#define BSLMF_METAINT_TO_BOOL(expr) BSLMF_TAG_TO_BOOL((expr).tag())
    // Given an integral value, 'V', and an expression, 'expr', of type
    // 'bslmf::MetaInt<V>', this macro returns a compile-time constant with
    // value, 'true' or 'false', according to the Boolean value of 'V'.  The
    // expression, 'expr', is not evaluated at run-time.

#ifndef BDE_OPENSOURCE_PUBLICATION  // BACKWARD_COMPATIBILITY
// ============================================================================
//                           BACKWARD COMPATIBILITY
// ============================================================================

#ifdef bslmf_MetaInt
#undef bslmf_MetaInt
#endif
#define bslmf_MetaInt bslmf::MetaInt
    // This alias is defined for backward compatibility.
#endif  // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY

// ============================================================================
//                            INLINE FUNCTIONS
// ============================================================================

// CREATORS
template <int t_INT_VALUE>
inline
MetaInt<t_INT_VALUE>::MetaInt()
{
}

template <int t_INT_VALUE>
inline
MetaInt<t_INT_VALUE>::MetaInt(bsl::integral_constant<int, t_INT_VALUE>)
{
}

inline
MetaInt<0>::MetaInt()
{
}

inline
MetaInt<0>::MetaInt(bsl::false_type)
{
}

inline
MetaInt<1>::MetaInt()
{
}

inline
MetaInt<1>::MetaInt(bsl::true_type)
{
}

// ACCESSORS
inline
MetaInt<0>::operator bool() const
{
    return false;
}

inline
MetaInt<1>::operator bool() const
{
    return true;
}

}  // close package namespace

}  // close enterprise namespace

#endif

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