// bslmf_isbitwiseequalitycomparable.h                                -*-C++-*-
#ifndef INCLUDED_BSLMF_ISBITWISEEQUALITYCOMPARABLE
#define INCLUDED_BSLMF_ISBITWISEEQUALITYCOMPARABLE

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

//@PURPOSE: Provide a type trait for bitwise equality.
//
//@CLASSES:
//  bslmf::IsBitwiseEqualityComparable: trait metafunction
//
//@DESCRIPTION: This component provides a single trait metafunction,
// 'bslmf::IsBitwiseEqualityComparable', which allows generic code to determine
// whether objects of the specified 't_TYPE' can be compared using 'memcmp'.
// Such types are said to be bitwise EqualityComparable.  Observe that this
// trait may be 'true' only for object types, even though, for example,
// reference types may be guaranteed identical bit representations when they
// refer to the same object, just as the corresponding pointer type would be
// bitwise EqualityComparable.
//
// For a type to be bitwise EqalityComparable, each bit of its object
// representation must be significant in the value representation, and distinct
// sequences of bits represent different values, i.e., this trait is an
// assertion that the specified 't_TYPE' has unique representations for each
// possible value, and no padding bits.  This property is deemed to hold for
// 'bool' and enumerations where, in practice, the compiler will enforce a
// value representation over all the seemingly unused bits.  For a C++17 tool
// chain, this trait should be equivalent to the
// 'std::has_unique_object_representation' trait.
//
// Note that as arrays are not allowed to introduce padding, arrays of a
// bitwise EqualityComparable 't_TYPE' are also bitwise EqualityComparable,
// even though they do not provide an overloaded 'operator=='.  While
// transforming comparisons of a single object using this trait into calls to
// 'memcmp' is unlikely to be profitable, transforming comparisons of a whole
// array into a single 'memcmp' call is more likely to be beneficial.
//
///Usage
///-----
//
///Example 1: Using the trait to optimize range comparison
///- - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Suppose we want to compare two sequences of the same object type to
// determine whether or not they hold the same values.  The simplest solution
// would be to iterate over both sequences, comparing each member, and return
// 'false' as soon as any pair of elements do not compare equal; if we walk all
// the way to the end of both sequences, then they hold the same values.  If we
// want to perform this comparison most efficiently though, we would rather not
// invoke 'operator==' on each member, and instead defer to the 'memcmp'
// function in the standard library that is highly optimized (often to take
// advantage of platform-specific instructions) for comparing ranges of raw
// memory.  We can switch to this other technique only if we know that the
// value representations of a type are unique, rely on all of the bits in their
// representation, and do not have strange values like 'NaN' that self-compare
// as 'false'.  This property is denoted by the 'IsBitwiseEqualityComparable'
// trait.
//
// First, we create a simple 'struct' that contains a 'char' and a 'short' as
// its two data members, and supported comparison with 'operator=='.  Note that
// there will be a byte of padding between the 'char' and the 'short' members
// to ensure proper alignment.  We insert telemetry to count the number of
// times 'operator==' is called:
//..
//  namespace BloombergLP {
//
//  struct SimpleType {
//      // This 'struct' holds two data members with a byte of padding, and can
//      // be compared using the overloaded 'operator=='.
//
//      char  d_dataC;
//      short d_dataS;
//
//      static int s_comparisons;
//
//      friend bool operator==(const SimpleType& a, const SimpleType& b)
//          // Return 'true' if the specified 'a' has the same value as the
//          // specified 'b'.  Two 'SimpleType' objects have the same value if
//          // their corresponding 'd_dataC' and 'd_dataS' members have the
//          // same value.  The static data member 's_comparisons' is
//          // incremented by one each time this function is called.
//      {
//          ++s_comparisons;
//          return a.d_dataC == b.d_dataC
//              && a.d_dataS == b.d_dataS;
//      }
//
//      friend bool operator!=(const SimpleType& a, const SimpleType& b)
//          // Return 'true' if the specified 'a' does not have the same value
//          // as the specified 'b'.  Two 'SimpleType' objects do not have the
//          // same value if their corresponding 'd_dataC' and 'd_dataS'
//          // members do not have the same value.  The static data member
//          // 's_comparisons' is incremented by one each time this function is
//          // called.
//      {
//          ++s_comparisons;
//          return a.d_dataC != b.d_dataC
//              || a.d_dataS != b.d_dataS;
//      }
//  };
//
//  int SimpleType::s_comparisons = 0;
//..
// Then, we create another 'struct' that wraps a single 'int' as its only data
// member, and supports comparison with 'operator==', inserting telemetry to
// count the number of times 'operator==' is called:
//..
//  struct SecondType {
//      // This 'struct' holds a single 'int' member, 'd_data', and can be
//      // compared using the overloaded 'operator=='.
//..
// We associate the bitwise EqualityComparable trait with 'SecondType' using
// the BDE nested trait declaration facility:
//..
//      BSLMF_NESTED_TRAIT_DECLARATION(SecondType,
//                                     bslmf::IsBitwiseEqualityComparable);
//
//      int d_data;
//
//      static int s_comparisons;
//
//      friend bool operator==(const SecondType& a, const SecondType& b)
//          // Return 'true' if the specified 'a' has the same value as the
//          // specified 'b'.  Two 'SecondType' objects have the same value if
//          // their corresponding 'd_data' elements have the same value.  The
//          // static data member 's_comparisons' is incremented by one each
//          // time this function is called.
//      {
//          ++s_comparisons;
//          return a.d_data == b.d_data;
//      }
//
//      friend bool operator!=(const SecondType& a, const SecondType& b)
//          // Return 'true' if the specified 'a' does not have the same value
//          // as the specified 'b'.  Two 'SecondType' objects do not have the
//          // same value if their corresponding 'd_data' elements do not have
//          // the same value.  The static data member 's_comparisons' is
//          // incremented by one each time this function is called.
//      {
//          ++s_comparisons;
//          return a.d_data != b.d_data;
//      }
//  };
//
//  int SecondType::s_comparisons = 0;
//..
// Next, we create another 'struct' that wraps a single 'int' as its only data
// member, and supports comparison with 'operator==', inserting telemetry to
// count the number of times 'operator==' is called:
//..
//  struct ThirdType {
//      // This 'struct' holds a single 'int' member, 'd_data', and can be
//      // compared using the overloaded 'operator=='.
//
//      int d_data;
//
//      static int s_comparisons;
//
//      friend bool operator==(const ThirdType& a, const ThirdType& b)
//          // Return 'true' if the specified 'a' has the same value as the
//          // specified 'b'.  Two 'SecondType' objects have the same value if
//          // their corresponding 'd_data' elements have the same value.  The
//          // static data member 's_comparisons' is incremented by one each
//          // time this function is called.
//      {
//          ++s_comparisons;
//          return a.d_data == b.d_data;
//      }
//
//      friend bool operator!=(const ThirdType& a, const ThirdType& b)
//          // Return 'true' if the specified 'a' does not have the same value
//          // as the specified 'b'.  Two 'ThirdType' objects do not have the
//          // same value if their corresponding 'd_data' elements do not have
//          // the same value.  The static data member 's_comparisons' is
//          // incremented by one each time this function is called.
//      {
//          ++s_comparisons;
//          return a.d_data != b.d_data;
//      }
//  };
//
//  int ThirdType::s_comparisons = 0;
//..
// We associate the bitwise EqualityComparable trait with 'ThirdType' by
// explicitly specializing the trait:
//..
//  namespace bslmf {
//      template <>
//      struct IsBitwiseEqualityComparable<ThirdType> : bsl::true_type {};
//  }  // close namespace bslmf
//..
// Now, we write a function template to compare two arrays of the same type:
//..
//  template <class t_TYPE>
//  bool rangeCompare(const t_TYPE *start, size_t length, const t_TYPE *other)
//  {
//..
// If we detect the bitwise EqualityComparable trait, we rely on the optimized
// 'memcmp' function:
//..
//      if (bslmf::IsBitwiseEqualityComparable<t_TYPE>::value) {
//          return 0 == memcmp(start,
//                             other,
//                             length * sizeof(t_TYPE));              // RETURN
//      }
//..
// Otherwise we iterate over the range directly until we find a pair of
// elements that do not have the same value, and return 'true' if we reach the
// end of the range.
//..
//      if (0 != length)  {
//          while (*start++ == *other++) {
//              if (!--length) {
//                  return true;                                      // RETURN
//              }
//          }
//      }
//      return false;
//  }
//..
// Finally, we write a test to confirm that two arrays containing different
// values do not compare as equal (using our array comparison function), and
// that an array compares equal to itself, as it does comprise elements all
// having the same value.  By inspecting the static data members provided for
// telemetry, we can confirm that 'operator==' is called only for 'SimpleType'
// as the other two 'struct's dispatch to 'memcmp' instead:
//..
//  int usageExample1()
//  {
//..
// We confirm the initial state of the telemetry:
//..
//      assert(0 == SimpleType::s_comparisons);
//      assert(0 == SecondType::s_comparisons);
//      assert(0 == ThirdType ::s_comparisons);
//..
// Then we create zero-initialized arrays for each of the types to be tested,
// and a second array for each type with a set of values distinct from all
// zeroes:
//..
//      const SimpleType simpleZeroes[10] = { };
//      const SecondType secondZeroes[10] = { };
//      const ThirdType  thirdZeroes [10] = { };
//
//      const SimpleType simpleValues[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
//      const SecondType secondValues[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
//      const ThirdType  thirdValues [10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
//..
// Next we confirm that the two arrays (of each type) do not compare equal, and
// inspect the telemetry to confirm that the comparison operator was called for
// only the 'SimpleType' without the bitwise EqualityComparable trait:
//..
//      assert(!rangeCompare(simpleZeroes, 10u, simpleValues) );
//      assert(!rangeCompare(secondZeroes, 10u, secondValues) );
//      assert(!rangeCompare(thirdZeroes,  10u, thirdValues)  );
//
//      assert(0 <  SimpleType::s_comparisons);
//      assert(0 == SecondType::s_comparisons);
//      assert(0 == ThirdType ::s_comparisons);
//
//..
// Then we reset the telemetry and confirm that an array of each type compares
// equal to itself, and inspect the telemetry to confirm that the comparison
// operator was called for only the 'SimpleType' without the bitwise
// EqualityComparable trait:
//..
//      SimpleType::s_comparisons = 0;
//
//      assert( rangeCompare(simpleValues, 10u, simpleValues) );
//      assert( rangeCompare(secondValues, 10u, secondValues) );
//      assert( rangeCompare(thirdZeroes,  10u, thirdZeroes)  );
//
//      assert(0 <  SimpleType::s_comparisons);
//      assert(0 == SecondType::s_comparisons);
//      assert(0 == ThirdType ::s_comparisons);
//
//      return 0;
//  }
//
//  }  // close enterprise namespace
//..
//
///Example 2: Associating a Trait with a Class Template
/// - - - - - - - - - - - - - - - - - - - - - - - - - -
// In this example, we associate a trait not with a class, but with a class
// *template*.  We create a "control" template that is not bitwise
// EqualityComparable, and two class templates, each of which uses a different
// mechanisms for being associated with the 'IsBitwiseEqualityComparable'
// trait.  First, we define a class template that is not bitwise
// EqualityComparable, 'NotComparable':
//..
//  namespace BloombergLP {
//
//  template <class t_TYPE>
//  struct NotComparable
//  {
//      t_TYPE d_value;
//  };
//..
// Then, we define the class template 'PotentiallyComparable1', which uses
// partial template specialization to associate the
// 'IsBitwiseEqualityComparable' trait with each instantiation on a 't_TYPE'
// that is itself bitwise EqualityComparable:
//..
//  template <class t_TYPE>
//  struct PotentiallyComparable1
//  {
//      t_TYPE d_value;
//  };
//
//  namespace bslmf {
//      template <class t_TYPE>
//      struct IsBitwiseEqualityComparable<PotentiallyComparable1<t_TYPE> >
//          : IsBitwiseEqualityComparable<t_TYPE>::type {
//      };
//  }  // close namespace bslmf
//..
// Next, we define the class template'PotentiallyComparable2', which uses the
// 'BSLMF_NESTED_TRAIT_DECLARATION' macro to associate the
// 'IsBitwiseEqualityComparable' trait with each instantiation on a 't_TYPE'
// that is itself bitwise EqualityComparable:
//..
//  template <class t_TYPE>
//  struct PotentiallyComparable2
//  {
//      t_TYPE d_value;
//
//      BSLMF_NESTED_TRAIT_DECLARATION_IF(
//                          PotentiallyComparable2,
//                          bslmf::IsBitwiseEqualityComparable,
//                          bslmf::IsBitwiseEqualityComparable<t_TYPE>::value);
//  };
//..
// Finally, we check that the traits are correctly associated by instantiating
// each template with types that are bitwise EqualityComparable and with types
// that are not not bitwise EqualityComparable, verifying the value of
// 'IsBitwiseEqualityComparable<T>::value' in each case:
//..
//  int usageExample2()
//  {
//      using namespace bslmf;
//
//      assert(!IsBitwiseEqualityComparable<NotComparable<int> >::value);
//      assert(!IsBitwiseEqualityComparable<
//                            NotComparable<NotComparable<int> > >::value);
//
//      assert( IsBitwiseEqualityComparable<
//                                 PotentiallyComparable1<int> >::value);
//      assert(!IsBitwiseEqualityComparable<
//                   PotentiallyComparable1<NotComparable<int> > >::value);
//
//      assert( IsBitwiseEqualityComparable<
//                                 PotentiallyComparable2<int> >::value);
//      assert(!IsBitwiseEqualityComparable<
//                   PotentiallyComparable2<NotComparable<int> > >::value);
//
//      return 0;
//  }
//
//  }  // close enterprise namespace
//..

#include <bslscm_version.h>

#include <bslmf_detectnestedtrait.h>
#include <bslmf_integralconstant.h>
#include <bslmf_isconst.h>
#include <bslmf_voidtype.h>

#include <bsls_platform.h>

#include <stddef.h>

#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
#include <bslmf_isenum.h>
#endif


namespace BloombergLP {
namespace bslmf {

template <class t_TYPE>
struct IsBitwiseEqualityComparable;

#if defined(BSLS_PLATFORM_CMP_IBM)
                     // =========================================
                     // struct IsBitwiseEqualityComparable_Scalar
                     // =========================================

template <class t_TYPE, class = void>
struct IsBitwiseEqualityComparable_Imp2 : bsl::false_type {
};
template <class t_TYPE>
struct IsBitwiseEqualityComparable_Imp2<t_TYPE, BSLMF_VOIDTYPE(t_TYPE[])>
: bsl::true_type {
    // This implementation-detail trait determines whether 't_TYPE' is a scalar
    // type (an arithmetic type, enumeration, pointer, or pointer-to-member).
    // This implementation takes advantage of a previous layer of filtering
    // handling all class-types, so any remaining types that are valid as array
    // elements must be scalar types, i.e., the 'BSLMF_VOIDTYPE' test will
    // filter function types and reference types.
};

                     // ======================================
                     // struct IsBitwiseEqualityComparable_Imp
                     // ======================================

template <class t_TYPE, class = void>
struct IsBitwiseEqualityComparable_Imp
: IsBitwiseEqualityComparable_Imp2<t_TYPE>::type {
};
template <class t_TYPE>
struct IsBitwiseEqualityComparable_Imp<t_TYPE, BSLMF_VOIDTYPE(int t_TYPE::*)>
: DetectNestedTrait<t_TYPE, IsBitwiseEqualityComparable>::type {
    // This trait 'struct' derives from 'bsl::true_type' if (the template
    // paramter) 't_TYPE' is a scalar type or a class with a nested trait
    // declaration for the 'bslmf::IsBitwiseEqualityComparable' trait, and from
    // 'bsl::false_type' otherwise.  Note that this template handles only the
    // class-type cases, delegating the final filtering for scalar types to a
    // further trait template.
};
#else
                     // ======================================
                     // struct IsBitwiseEqualityComparable_Imp
                     // ======================================

template <class t_TYPE, class = void>
struct IsBitwiseEqualityComparable_Imp : bsl::is_const<const t_TYPE>::type {
};
template <class t_TYPE>
struct IsBitwiseEqualityComparable_Imp<t_TYPE, BSLMF_VOIDTYPE(int t_TYPE::*)>
: DetectNestedTrait<t_TYPE, IsBitwiseEqualityComparable>::type {
    // This trait 'struct' derives from 'bsl::true_type' if (the template
    // paramter) 't_TYPE' is a scalar type or a class with a nested trait
    // declaration for the 'bslmf::IsBitwiseEqualityComparable' trait, and from
    // 'bsl::false_type' otherwise.  Note that this implementation relies on
    // the fact that reference and function types cannot be cv-qualified, and
    // any other non-class type (that is not handled by specializations of the
    // primary template) will be a scalar type.
};
#endif

                     // ==================================
                     // struct IsBitwiseEqualityComparable
                     // ==================================

template <class t_TYPE>
struct IsBitwiseEqualityComparable
: IsBitwiseEqualityComparable_Imp<t_TYPE>::type {
    // This trait 'struct' is a metafunction that determines whether the
    // specified parameter 't_TYPE' is bitwise EqualityComparable.  If
    // 'IsBitwiseEqualityComparable<t_TYPE>' is derived from 'true_type' then
    // 't_TYPE' is bitwise EqualityComparable.  Otherwise, bitwise equality
    // comparability cannot be inferred for 't_TYPE'.  This trait can be
    // associated with a bitwise EqualityComparable user-defined class by
    // specializing this class or by using the 'BSLMF_NESTED_TRAIT_DECLARATION'
    // macro.
};

template <class t_TYPE>
struct IsBitwiseEqualityComparable<const t_TYPE>
: IsBitwiseEqualityComparable<t_TYPE>::type {
};
template <class t_TYPE>
struct IsBitwiseEqualityComparable<volatile t_TYPE>
: IsBitwiseEqualityComparable<t_TYPE>::type {
};
template <class t_TYPE>
struct IsBitwiseEqualityComparable<const volatile t_TYPE>
: IsBitwiseEqualityComparable<t_TYPE>::type {
};
    // Partial specializations for cv-qualified types channel to a single
    // instantiation of the implementation type.  Note that we cannot derive
    // through the 'Imp' type directly as we would not correctly handle
    // cv-qualified types that have been explicitly specialized by our users.

template <class t_TYPE, size_t t_LEN>
struct IsBitwiseEqualityComparable<t_TYPE[t_LEN]>
: IsBitwiseEqualityComparable<t_TYPE>::type {
};
template <class t_TYPE, size_t t_LEN>
struct IsBitwiseEqualityComparable<const t_TYPE[t_LEN]>
: IsBitwiseEqualityComparable<t_TYPE>::type {
};
template <class t_TYPE, size_t t_LEN>
struct IsBitwiseEqualityComparable<volatile t_TYPE[t_LEN]>
: IsBitwiseEqualityComparable<t_TYPE>::type {
};
template <class t_TYPE, size_t t_LEN>
struct IsBitwiseEqualityComparable<const volatile t_TYPE[t_LEN]>
: IsBitwiseEqualityComparable<t_TYPE>::type {
};

template <class t_TYPE>
struct IsBitwiseEqualityComparable<t_TYPE[]>
: IsBitwiseEqualityComparable<t_TYPE>::type {
};
template <class t_TYPE>
struct IsBitwiseEqualityComparable<const t_TYPE[]>
: IsBitwiseEqualityComparable<t_TYPE>::type {
};
template <class t_TYPE>
struct IsBitwiseEqualityComparable<volatile t_TYPE[]>
: IsBitwiseEqualityComparable<t_TYPE>::type {
};
template <class t_TYPE>
struct IsBitwiseEqualityComparable<const volatile t_TYPE[]>
: IsBitwiseEqualityComparable<t_TYPE>::type {
};
    // Partial specializations for array types, as arrays have a contiguity
    // guarantee (that can inferred from pointer arithmetic rules) so this if a
    // type is bitwise equality comparable, we can be sure there is no padding
    // introduced by an array, so arrays of this type should have the same
    // property.

template <>
struct IsBitwiseEqualityComparable<void> : bsl::false_type {};
    // Explicit specialization to confirm that 'void' types are never bitwise
    // EqualityComparable.  Note that cv-'void' types are covered by the
    // partial specialization for any cv-qualified type.

template <>
struct IsBitwiseEqualityComparable<float> : bsl::true_type {};
template <>
struct IsBitwiseEqualityComparable<double> : bsl::true_type {};
template <>
struct IsBitwiseEqualityComparable<long double> : bsl::true_type {};
    // Revert of {DRQS 143286899}. Once clients are fixed, change to false.
    // Explicit specialization to confirm that floating point types are not
    // bitwise EqualityComparable, as they typically have specific problematic
    // values: NaNs do not compare equal with themselves, and there may be
    // multiple representations for zero (with negative zero).

}  // close package namespace
}  // close enterprise namespace

#endif // ! defined(INCLUDED_BSLMF_ISBITWISEEQUALITYCOMPARABLE)

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