// bslmf_tag.h                                                        -*-C++-*-
#ifndef INCLUDED_BSLMF_TAG
#define INCLUDED_BSLMF_TAG

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

//@PURPOSE: Provide an integral-constant-to-type conversion.
//
//@CLASSES:
//  bslmf::Tag: map integral constants to C++ types
//
//@MACROS:
//: BSLMF_TAG_TO_INT(EXPR): map tag to integral value
//: BSLMF_TAG_TO_BOOL(EXPR): map tag to boolean value
//
//@DESCRIPTION: This component defines a simple template structure used to map
// an integral constant to a C++ type.  'bslmf::Tag<unsigned>' 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::Tag<0>' is a distinct type from 'bslmf::Tag<1>', which, in
// turn, is also distinct from 'bslmf::Tag<2>', and so on.
//
// This component also provides two macros for mapping a 'bslmf::Tag<t_N>'
// instance to the integral value 't_N' ('BSLMF_TAG_TO_INT'), and to the
// boolean value 't_N != 0' ('BSLMF_TAG_TO_BOOL').
//
///Macro Summary
///-------------
// This section provides a brief description of the macros defined in this
// component.
//
//: 'BSLMF_TAG_TO_INT(EXPR)'
//:     Given an integral value, 'V', and an expression, 'EXPR', of type
//:     'bslmf::Tag<V>', this macro returns a compile-time constant with the
//:     value 'V'.  'EXPR' is not evaluated at run-time.
//:
//: 'BSLMF_TAG_TO_BOOL(EXPR)'
//:     Given an integral value, 'V', and an expression, 'EXPR', of type
//:     'bslmf::Tag<V>', this macro returns a compile-time constant with the
//:     value 'true' or 'false', depending on the boolean value of 'V'.  'EXPR'
//:     is not evaluated at run-time.
//

///Usage
///-----
// 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::Tag<0> *)
//  {
//      // slow but generic implementation
//  }
//
//  template <class T>
//  void doSomethingImp(T *t, bslmf::Tag<1> *)
//  {
//      // fast implementation (appropriate for bitwise-movable types)
//  }
//
//  template <class T, bool IsFast>
//  void doSomething(T *t)
//  {
//      doSomethingImp(t, (bslmf::Tag<IsFast> *)0);
//  }
//..
// For some parameter types, the fast version of 'doSomethingImp' is not legal.
// The power of this approach is that the compiler will compile just the
// implementation selected by the tag argument.
//..
//  void f()
//  {
//      int i;
//      doSomething<int, true>(&i);      // fast version selected for 'int'
//
//      double m;
//      doSomething<double, false>(&m);  // slow version selected for 'double'
//  }
//..
// Note that an alternative design would be to use template partial
// specialization instead of standard function overloading to avoid the cost of
// passing a 'bslmf::Tag<t_N>' pointer.
//
// The value of the integral parameter supplied to an instantiation of
// 'bslmf::Tag<t_N>' is "recoverable" by using the 'BSLMF_TAG_TO_INT' macro.
// For example:
//..
//  bslmf::Tag<7> tag;
//  assert( 7 == BSLMF_TAG_TO_INT(tag));
//  assert(53 == BSLMF_TAG_TO_INT(bslmf::Tag<50 + 3>()));
//..
// The 'BSLMF_TAG_TO_BOOL' macro can be used to determine if the parameter is
// non-zero:
//..
//  assert( 1 == BSLMF_TAG_TO_BOOL(tag));
//  assert( 0 == BSLMF_TAG_TO_BOOL(bslmf::Tag<0>()));
//..

#include <bslscm_version.h>

#include <bsls_platform.h>

namespace BloombergLP {

namespace bslmf {

                              // ===============
                              // struct Tag<t_N>
                              // ===============

template <unsigned t_N>
struct Tag {
    // This template class is never intended to produce a run-time instance.
    // The only useful attribute of a tag is its size (which is, of course,
    // computable at compile time, even if an instance is never created).  Note
    // that in case of overflow on Linux 64-bit machines, we split the size
    // into 2 data members.

    // DATA
    char d_upperSizeArray[(t_N >> 16) + 1];
    char d_lowerSizeArray[(t_N&  0x0000FFFF) + 1];
};

}  // close package namespace

#define BSLMF_TAG_TO_UINT(BSLMF_EXPR)                                        \
                         (((sizeof(BSLMF_EXPR.d_upperSizeArray) - 1) << 16)  \
                         | (sizeof(BSLMF_EXPR.d_lowerSizeArray) - 1))

#define BSLMF_TAG_TO_INT(BSLMF_EXPR) ((int)BSLMF_TAG_TO_UINT(BSLMF_EXPR))

#define BSLMF_TAG_TO_BOOL(BSLMF_EXPR) (BSLMF_TAG_TO_INT(BSLMF_EXPR) != 0)

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

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

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