// bslh_hash.h                                                        -*-C++-*-
#ifndef INCLUDED_BSLH_HASH
#define INCLUDED_BSLH_HASH

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

//@PURPOSE: Provide a struct to run 'bslh' hash algorithms on supported types.
//
//@CLASSES:
//  bslh::Hash: functor that runs 'bslh' hash algorithms on supported types
//
//@SEE_ALSO:
//
//@DESCRIPTION: This component provides a templated 'struct', 'bslh::Hash',
// that defines a hash-functor that can be used with standard containers (a
// drop in replacement for 'bsl::hash'), and which applies the supplied
// (template parameter) 'HASH_ALGORITHM' to the attributes of the (template
// parameter) 'TYPE' which have been identified as salient to hashing.  The
// 'bslh::Hash' template parameter 'HASH_ALGORITHM' must be a hashing algorithm
// that conforms to the requirements outlined below (see {Requirements for
// Regular 'bslh' Hashing Algorithms}).  Note that there are several hashing
// algorithms defined within the 'bslh' package and some, such as those that
// require seeds, will not meet these requirements, meaning they cannot be used
// with 'bslh::Hash'.  A call to 'bslh::Hash::operator()' for a (template
// parameter) 'TYPE' will call the 'hashAppend' free function for 'TYPE' and
// provide 'hashAppend' an instance of a hash algorithm in the 'bslh' namespace
// that will use the (template parameter) 'HASH_ALGORITHM' to compute hash
// values.
//
// This component also contains 'hashAppend' definitions for fundamental types,
// which are required by algorithms defined in 'bslh'.  Clients are expected to
// define a free-function 'hashAppend' for each of the types they wish to be
// hashable (see {'hashAppend'} below).  More information can be found in the
// package level documentation for 'bslh' (internal users can also find
// information here {TEAM BDE:USING MODULAR HASHING<GO>})
//
///Modularity
///----------
// 'bslh::Hash' provides a modular system for hashing.  This modularity refers
// to the decoupling of the various tasks associated with hashing.  Using this
// system, type implementers can identify attributes of their type that are
// salient to hashing, without having to write a hashing algorithm.
// Conversely, hashing algorithms can be written independent of types.
// Attributes that are salient to hashing are called out on a type using
// 'hashAppend'.  Hashing algorithms are written to operate on the attributes
// called out by 'hashAppend'.  Some default algorithms have been provided in
// the 'bslh' package.  This modularity allows type creators to avoid writing
// hashing algorithms, which can save work and avoid bad hashing algorithm
// implementations.
//
///'hashAppend'
///------------
// 'hashAppend' is the free function that is used to pass attributes that are
// salient to hashing into a hashing algorithm.  A custom type defined in
// another component must define it's own 'hashAppend' free function overload
// that can be discovered through ADL in order to be hashed using this
// facility.  A simple implementation of an overload for 'hashAppend' might
// call 'hashAppend' on each of the type's fields that are salient to hashing.
// Note that when writing a 'hashAppend' function that itself calls
// 'hashAppend, 'using bslh::hashAppend;' must be included as the first line of
// code in the function.  The using statement ensures that ADL will always be
// able to find the 'hashAppend' functions defined in this component for
// handling fundamental types even when the (template parameter) type
// 'HASH_ALGORITHM' is not implemented in 'bslh'.
//
// A client will thus customize their hashing of any custom 'struct', 'class',
// or 'union' by providing an appropriate 'hashAppend'.  In some very rare
// cases, a client will want to provide special behavior when hashing
// fundamental types such as integral types, pointers, or enums, and this can
// be done by providing an appropriate typed 'operator()' overload of your own
// hash function.  Support for doing this is not provided for ther types, or
// for 'bool'.
//
// Some types may require more subtle implementations for 'hashAppend', such as
// types containing C-strings which are salient to hashing.  These C-strings
// must be passed directly into the (template parameter) type 'HASH_ALGORITHM',
// rather than calling 'hashAppend' with the pointer as an argument.  This
// special case exists because calling 'hashAppend' with a pointer will hash
// the pointer rather than the data that is pointed to.
//
// Within this component, 'hashAppend' has been implemented for all of the
// fundamental types, and for arrays.  When 'hashAppend' is reached on a
// fundamental type, the hashing algorithm is no longer propagated, and instead
// a pointer to the beginning of the type in memory is passed to the algorithm,
// along with the length of the type.  There are special cases with floating
// point numbers and boolean values where the data is tweaked before hashing to
// ensure that values that compare equal will be hashed with the same bit-wise
// representation.  The algorithm will then incorporate the type into its
// internal state and return a finalized hash when requested.
//
///Hashing Algorithms
///------------------
// There are algorithms implemented in the 'bslh' package that can be passed in
// and used as template parameters for 'bslh::Hash' or other 'struct's like it.
// Some of these algorithms, such as 'bslh::SpookyHashAlgorithm' or
// 'bslh::WyHashAlgorithm', are named for the algorithm they implement.  These
// named algorithms are intended for use by those who want a specific
// algorithm.  There are other algorithms, such as
// 'bslh::DefaultHashAlgorithm', which wrap an unspecified algorithm and
// describe the properties of the wrapped algorithm.  The descriptive
// algorithms are intended for use by those who need specific properties and
// want to be updated to a new algorithm when one is published with
// improvements to the desired properties.  'bslh::DefaultHashAlgorithm' has
// the property of being a good default algorithm, specifically for use in a
// hash table.
//
///Requirements for Regular 'bslh' Hashing Algorithms
///--------------------------------------------------
// Users of this modular hashing system are free to write their own hashing
// algorithms.  In order to plug into 'bslh::Hash', the user-implemented
// algorithms must implement the interface shown here:
//..
// class SomeHashAlgorithm
// {
//   public:
//     // TYPES
//     typedef Uint64 result_type;
//
//     // CREATORS
//     SomeHashAlgorithm();
//
//     // MANIPULATORS
//     void operator()(const void *data, size_t numBytes);
//
//     result_type computeHash();
// };
//..
// The 'result_type' 'typedef' must define the return type of this particular
// algorithm.  A default constructor (either implicit or explicit) must be
// supplied that creates an algorithm functor that is in a usable state.  An
// 'operator()' must be supplied that takes a 'const void *' to the data to be
// hashed and a 'size_t' length of bytes to be hashed.  This operator must
// operate on all data uniformly, meaning that regardless of whether data is
// passed in all at once, or one byte at a time, the result returned by
// 'computeHash()' will be the same.  'computeHash()' will return the final
// result of the hashing algorithm, as type 'result_type'.  'computeHash()' is
// allowed to modify the internal state of the algorithm, meaning calling
// 'computeHash()' more than once may not return the correct value.
//
///Subdivision-Invariance
/// - - - - - - - - - - -
// The result produced by the hashing algorithm must be independent of how the
// data is subdivided into segments when supplied to 'operator()'.  More
// precisely, for any subdivision of the message 'M' of size 'S' into 'N'
// segments 'M_i' of size 'S_i', the following must be true:
//
//..
//  SomeHashAlgorithm algM;
//  algM(M, S);
//
//  SomeHashAlgorithm algI;
//  for (int i = 0; i < N; ++i) {
//      algI(M_i, S_i);
//  }
//
//  assert(algM.computeHash() == algI.computeHash());
//..
//
///Usage
///-----
// This section illustrates intended usage of this component.
//
///Example 1: Keying a Hash Table with a User-Defined Type
///- - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Suppose we have a value-semantic type, 'Box', that contains attributes that
// are salient to hashing as well as attributes that are not salient to
// hashing.  Some of these attributes are themselves user defined types.  We
// want to store objects of type 'Box' in a hash table, so we need to be able
// to produce hash values that represent instances of 'Box'.  We don't want to
// write our own hashing or hash combine algorithm, because we know it is very
// difficult and labor-intensive to write a proper hashing algorithm.  In order
// to hash this 'Box', we will use the modular hashing system supplied in
// 'bslh'.
//
// First, we define 'Point', a class that allows us to identify a location on a
// two dimensional Cartesian plane.
//..
//  class Point {
//      // This class is a value-semantic type that represents a two
//      // dimensional location on a Cartesian plane.
//
//    private:
//      int    d_x;
//      int    d_y;
//      double d_distToOrigin; // This value will be accessed frequently, so we
//                             // cache it rather than recalculate it every
//                             // time.
//
//    public:
//      Point (int x, int y);
//          // Create a 'Point' having the specified 'x' and 'y' coordinates.
//
//      double distanceToOrigin() const;
//          // Return the distance from the origin (0, 0) to this point.
//
//      int getX() const;
//          // Return the x coordinate of this point.
//
//      int getY() const;
//          // Return the y coordinate of this point.
//  };
//
//  inline
//  Point::Point(int x, int y)
//  : d_x(x)
//  , d_y(y)
//  {
//      d_distToOrigin = sqrt(static_cast<double>(d_x * d_x) +
//                            static_cast<double>(d_y * d_y));
//  }
//
//  inline
//  double Point::distanceToOrigin() const
//  {
//      return d_distToOrigin;
//  }
//
//  inline
//  int Point::getX() const
//  {
//      return d_x;
//  }
//
//  inline
//  int Point::getY() const
//  {
//      return d_y;
//  }
//..
// Then, we define 'operator=='.  Notice how it checks only attributes that we
// would want to incorporate into the hashed value.  Note that attributes that
// are salient to hashing tend to be the same as or a subset of the attributes
// that are checked in 'operator=='.
//..
//  bool operator==(const Point& lhs, const Point& rhs)
//      // Return true if the specified 'lhs' and 'rhs' have the same value.
//      // Two 'Point' objects have the same value if they have the same x and
//      // y coordinates.
//  {
//      return (lhs.getX() == rhs.getX()) && (lhs.getY() == rhs.getY());
//  }
//..
// Next, we define 'hashAppend'.  This function will allow any hashing
// algorithm that meets the 'bslh' hashing algorithm requirements to be applied
// to 'Point'.  This is the full extent of the work that needs to be done by
// type creators.  They do not need to implement any algorithms, they just need
// to call out the attributes that are salient to hashing by calling
// 'hashAppend' on them.
//..
//  template <class HASH_ALGORITHM>
//  void hashAppend(HASH_ALGORITHM& hashAlg, const Point& point)
//      // Apply the specified 'hashAlg' to the specified 'point'
//  {
//      using bslh::hashAppend;
//      hashAppend(hashAlg, point.getX());
//      hashAppend(hashAlg, point.getY());
//  }
//..
// Then, we declare another value-semantic type, 'Box' that will have a 'Point'
// as one of its attributes that are salient to hashing.
//..
//  class Box {
//      // This class is a value-semantic type that represents a box drawn on
//      // to a Cartesian plane.
//
//    private:
//      Point d_position;
//      int d_length;
//      int d_width;
//
//    public:
//      Box(Point position, int length, int width);
//          // Create a box having the specified 'length' and 'width', with its
//          // upper left corner at the specified 'position'
//
//      int getLength() const;
//          // Return the length of this box.
//
//      Point getPosition() const;
//          // Return a 'Point' representing the upper left corner of this box
//          // on a Cartesian plane
//
//      int getWidth() const;
//          // Return the width of this box.
//  };
//
//  inline
//  Box::Box(Point position, int length, int width)
//  : d_position(position)
//  , d_length(length)
//  , d_width(width) { }
//
//  int Box::getLength() const
//  {
//      return d_length;
//  }
//
//  Point Box::getPosition() const
//  {
//      return d_position;
//  }
//
//  int Box::getWidth() const
//  {
//      return d_width;
//  }
//..
// Then, we define 'operator=='.  This time all of the data members are salient
// to equality.
//..
//  bool operator==(const Box& lhs, const Box& rhs)
//      // Return true if the specified 'lhs' and 'rhs' have the same value.
//      // Two 'Box' objects have the same value if they have the same length,
//      // width, and position.
//  {
//      return (lhs.getPosition() == rhs.getPosition()) &&
//             (lhs.getLength()   == rhs.getLength()) &&
//             (lhs.getWidth()    == rhs.getWidth());
//  }
//..
// Next, we define 'hashAppend' for 'Box'.  Notice how as well as calling
// 'hashAppend' on fundamental types, we can also call it with our user defined
// type 'Point'.  Calling 'hashAppend' with 'Point' will propogate a reference
// to the hashing algorithm functor 'hashAlg' down to the fundamental types
// that make up 'Point', and those types will then be passed into the
// referenced algorithm functor.
//..
//  template <class HASH_ALGORITHM>
//  void hashAppend(HASH_ALGORITHM& hashAlg, const Box& box)
//      // Apply the specified 'hashAlg' to the specified 'box'
//  {
//      using bslh::hashAppend;
//      hashAppend(hashAlg, box.getPosition());
//      hashAppend(hashAlg, box.getLength());
//      hashAppend(hashAlg, box.getWidth());
//  }
//..
// Then, we declare our hash table (implementation elided).  We simplify the
// problem by requiring the caller to supply an array.  Our hash table takes
// two type parameters: 'TYPE' (the type being referenced) and 'HASHER' (a
// functor that produces the hash).  'HASHER' will default to 'bslh::Hash<>'.
//..
//  template <class TYPE, class HASHER = bslh::Hash<> >
//  class HashTable {
//      // This class template implements a hash table providing fast lookup of
//      // an external, non-owned, array of values of (template parameter)
//      // 'TYPE'.
//      //
//      // The (template parameter) 'TYPE' shall have a transitive, symmetric
//      // 'operator==' function and it will be hashable using 'bslh::Hash'.
//      // Note that there is no requirement that it have any kind of creator
//      // defined.
//      //
//      // The 'HASHER' template parameter type must be a functor with a method
//      // having the following signature:
//      //..
//      //  size_t operator()(TYPE)  const;
//      //                   -OR-
//      //  size_t operator()(const TYPE&) const;
//      //..
//      // and 'HASHER' shall have a publicly accessible default constructor
//      // and destructor.  Here we use 'bslh::Hash' as our default template
//      // argument.  This allows us to hash any type for which 'hashAppend'
//      // has been implemented.
//      //
//      // Note that this hash table has numerous simplifications because we
//      // know the size of the array and never have to resize the table.
//
//      // DATA
//      const TYPE       *d_values;             // Array of values table is to
//                                              // hold
//      size_t            d_numValues;          // Length of 'd_values'.
//      const TYPE      **d_bucketArray;        // Contains ptrs into
//                                              // 'd_values'
//      size_t            d_bucketArrayMask;    // Will always be '2^N - 1'.
//      HASHER            d_hasher;
//
//    private:
//      // PRIVATE ACCESSORS
//      bool lookup(size_t      *idx,
//                  const TYPE&  value,
//                  size_t       hashValue) const;
//          // Look up the specified 'value', having the specified 'hashValue',
//          // and load its index in 'd_bucketArray' into the specified 'idx'.
//          // If not found, return the vacant entry in 'd_bucketArray' where
//          // it should be inserted.  Return 'true' if 'value' is found and
//          // 'false' otherwise.
//
//    public:
//      // CREATORS
//      HashTable(const TYPE *valuesArray,
//                size_t      numValues);
//          // Create a hash table referring to the specified 'valuesArray'
//          // having length of the specified 'numValues'.  No value in
//          // 'valuesArray' shall have the same value as any of the other
//          // values in 'valuesArray'
//
//      ~HashTable();
//          // Free up memory used by this hash table.
//
//      // ACCESSORS
//      bool contains(const TYPE& value) const;
//          // Return true if the specified 'value' is found in the table and
//          // false otherwise.
//  };
//..
// Next, we will create an array of boxes that we want to store in our hash
// table.
//..
//
//        Box boxes[] = { Box(Point(1, 1), 3, 2),
//                        Box(Point(3, 1), 4, 2),
//                        Box(Point(1, 2), 3, 3),
//                        Box(Point(1, 1), 2, 2),
//                        Box(Point(1, 4), 4, 3),
//                        Box(Point(2, 1), 4, 2),
//                        Box(Point(1, 0), 3, 1)};
//        enum { NUM_BOXES = sizeof boxes / sizeof *boxes };
//
//..
// Then, we create our hash table 'hashTable'.  We pass we use the default
// functor which will pick up the 'hashAppend' function we created:
//..
//
//        HashTable<Box> hashTable(boxes, NUM_BOXES);
//..
// Now, we verify that each element in our array registers with count:
//..
// for ( int i = 0; i < 6; ++i) { ASSERT(hashTable.contains(boxes[i])); }
//..
// Finally, we verify that futures not in our original array are correctly
// identified as not being in the set:
//..
// ASSERT(!hashTable.contains(Box(Point(1, 1), 1, 1)));
// ASSERT(!hashTable.contains(Box(Point(0, 0), 0, 0)));
// ASSERT(!hashTable.contains(Box(Point(3, 3), 3, 3)));
//..

#include <bslscm_version.h>

#include <bslh_defaulthashalgorithm.h>

#include <bslmf_enableif.h>
#include <bslmf_isbitwisemoveable.h>
#include <bslmf_isenum.h>
#include <bslmf_isfloatingpoint.h>
#include <bslmf_isintegral.h>
#include <bslmf_ispointer.h>
#include <bslmf_issame.h>
#include <bslmf_istriviallycopyable.h>
#include <bslmf_istriviallydefaultconstructible.h>

#include <bsls_compilerfeatures.h>
#include <bsls_platform.h>

#include <stddef.h>  // for 'size_t'

namespace BloombergLP {
namespace bslh {

                      // ===========================
                      // class bslh::Hash_AdlWrapper
                      // ===========================

template <class HASH_ALGORITHM>
class Hash_AdlWrapper {
    // This 'class' is a wrapper that is useful in the case of 'HASH_ALGORITHM'
    // not being in the 'bslh' namespace, which can be problematic for ADL
    // lookup of 'bslh::hashAppend'.  Wrapping a hash algorithm in this
    // wrapper, which is called inline, effectively forwards the algorithm into
    // the 'bslh' namespace.
    //
    // More detailed explanation:
    //
    // Normally, we define the free functions 'hashAppend' in the same
    // namespaces as the types they are hashing, so that ADL will find the
    // function.  In cases where this is not possible, such as 'std', we
    // support defining a 'hashAppend' overload in the 'bslh' namespace
    // instead.  This wrapper makes sure that 'bslh' is an associated namespace
    // when it is used as the first argument to 'hashAppend', ensuring that
    // such overloads in 'bslh' added outside this component are still found
    // via ADL.  Without this wrapper, in the cases where the hash algorithm is
    // neither in 'bslh' nor in the namespace of the hashed type, ADL then
    // fails to find the function.
    //
    // This wrapper solves this problem by forcibly associating the invocation
    // of 'hashAppend', wherever it may be, with the 'bslh' namespace.

  public:
    typedef typename HASH_ALGORITHM::result_type result_type;

  private:
    // DATA
    HASH_ALGORITHM d_hashAlgorithm;    // the wrapped hash algorithm, which may
                                       // be in any namespace

  public:
    // CREATORS
    Hash_AdlWrapper();
        // Default construct an instance of the hash algorithm wrapped in this
        // wrapper.

    // MANIPULATORS
    void operator()(const void *input, size_t numBytes);
        // Forward the call to the identical manipulator of 'HASH_ALGORITHM',
        // passing on the specified 'input' and 'numBytes'.

    template <class ELEMENT_TYPE>
    void operator()(const ELEMENT_TYPE *input, size_t numBytes);
        // Forward the call to the identical manipulator of 'HASH_ALGORITHM',
        // passing on the specified 'input' and 'numBytes'.

    result_type computeHash();
        // Forward the call to the identical manipulator of 'HASH_ALGORITHM'
        // and cast the return value to 'result_type.
};

                          // ================
                          // class bslh::Hash
                          // ================

template <class HASH_ALGORITHM = bslh::DefaultHashAlgorithm>
struct Hash {
    // This struct wraps the (template parameter) type 'HASH_ALGORITHM' in an
    // interface that satisfies the 'hash' requirements of the C++11 standard.

    // TYPES
    typedef size_t result_type;
        // The type of the hash value that will be returned by the
        // function-call operator.

    typedef HASH_ALGORITHM HashAlgorithm;
        // Make the 'HASH_ALGORITHM' template parameter available to clients.

    // CREATORS
    //! Hash() = default;
        // Create a 'bslh::Hash' object.

    //! Hash(const Hash& original) = default;
        // Create a 'bslh::Hash' object.  Note that as 'bslh::Hash' is an empty
        // (stateless) type, this operation will have no observable effect.

    //! ~Hash() = default;
        // Destroy this object.

    // MANIPULATORS
    //! Hash& operator=(const Hash& rhs) = default;
        // Assign to this object the value of the specified 'rhs' object, and
        // return a reference providing modifiable access to this object.  Note
        // that as 'bslh::Hash' is an empty (stateless) type, this operation
        // will have no observable effect.

    // ACCESSORS
    template <class TYPE>
    result_type operator()(const TYPE& type) const;
        // Returns a hash value generated by the (template parameter) type
        // 'HASH_ALGORITHM' for the specified 'type'.  The value returned by
        // the 'HASH_ALGORITHM' is cast to 'size_t' before returning.

};

// FREE FUNCTIONS
template <class HASH_ALGORITHM, class TYPE>
inline
typename bsl::enable_if<
    (bsl::is_integral<TYPE>::value ||
     bsl::is_pointer<TYPE>::value  ||
     bsl::is_enum<TYPE>::value)    &&
    !bsl::is_same<TYPE, bool>::value
>::type
hashAppend(HASH_ALGORITHM& hashAlg, TYPE input)
    // Passes the specified 'input' into the specified 'hashAlg' to be combined
    // into the internal state of the algorithm which is used to produce the
    // resulting hash value.  Note that the 'enable_if' meta-function is used
    // to enable this 'hashAppend' function for only integral (excluding
    // 'bool'), pointer, and enum types, because these types can all be hashed
    // as a continuous sequence of bytes.  Also note that this function is
    // defined inline because MS Visual Studio compilers before 2013 require
    // (some) functions declared using enable_if be in-place inline.
{
    hashAlg(&input, sizeof(input));
}

template <class HASH_ALGORITHM, class TYPE>
inline
typename bsl::enable_if<
    bsl::is_floating_point<TYPE>::value &&
   !bsl::is_same<TYPE, long double>::value
>::type
hashAppend(HASH_ALGORITHM& hashAlg, TYPE input)
    // Passes the specified 'input' into the specified 'hashAlg' to be combined
    // into the internal state of the algorithm which is used to produce the
    // resulting hash value.  Note that the 'enable_if' meta-function is used
    // to enable this 'hashAppend' function for only floating point (excluding
    // 'long double') types, because these types need to have +/-0.0 normalized
    // to 0.0 before they can be hashed as a continuous sequence of bytes.
    // Also note that this function is defined inline because MS Visual Studio
    // compilers before 2013 require (some) functions declared using enable_if
    // be in-place inline.
{
    if (input == 0)
        input = 0;
    hashAlg(&input, sizeof(input));
}

template <class HASH_ALGORITHM, class TYPE>
typename bsl::enable_if< bsl::is_same<TYPE, bool>::value >::type
hashAppend(HASH_ALGORITHM& hashAlg, TYPE input);
    // Passes the specified 'input' into the specified 'hashAlg' to be combined
    // into the internal state of the algorithm which is used to produce the
    // resulting hash value.  Note that the 'enable_if' meta-function is used
    // to enable this 'hashAppend' function for only 'bool', because 'bool's
    // can have multiple 'true' representations and need to be normalized
    // before they can be hashed as a continuous sequence of bytes.

template <class HASH_ALGORITHM, class TYPE>
typename bsl::enable_if< bsl::is_same<TYPE, long double>::value >::type
hashAppend(HASH_ALGORITHM& hashAlg, TYPE input);
    // Passes the specified 'input' into the specified 'hashAlg' to be combined
    // into the internal state of the algorithm which is used to produce the
    // resulting hash value.  Note that the 'enable_if' meta-function is used
    // to enable this 'hashAppend' function for only 'long double', because on
    // some compilers 'long double's contain garbage and can not be hashed as a
    // continuous sequence of bytes.

template <class HASH_ALGORITHM, size_t N>
void hashAppend(HASH_ALGORITHM& hashAlg, char (&input)[N]);
    // Passes the specified 'input' into the specified 'hashAlg' to be combined
    // into the internal state of the algorithm which is used to produce the
    // resulting hash value.  Note that the entire 'char' array will be hashed
    // in only one call to 'hashAlg'.  Also note that this 'hashAppend' exists
    // because some platforms don't recognize that adding a const qualifier is
    // a better match for arrays than decaying to a pointer and using the
    // 'hashAppend' function for pointers.

template <class HASH_ALGORITHM, size_t N>
void hashAppend(HASH_ALGORITHM& hashAlg, const char (&input)[N]);
    // Passes the specified 'input' into the specified 'hashAlg' to be combined
    // into the internal state of the algorithm which is used to produce the
    // resulting hash value.  Note that the entire 'char' array will be hashed
    // in only one call to 'hashAlg'.

template <class HASH_ALGORITHM, class TYPE, size_t N>
void hashAppend(HASH_ALGORITHM& hashAlg, TYPE (&input)[N]);
    // Passes the specified 'input' into the specified 'hashAlg' to be combined
    // into the internal state of the algorithm which is used to produce the
    // resulting hash value.  Note that the elements in 'input' will be hashed
    // one at a time by calling 'hashAppend' because the (template parameter)
    // 'TYPE' might not be hashable as a contiguous sequence of bytes.  Also
    // note that this 'hashAppend' exists because some platforms don't
    // recognize that adding a const qualifier is a better match for arrays
    // than decaying to a pointer and using the 'hashAppend' function for
    // pointers.

template <class HASH_ALGORITHM, class TYPE, size_t N>
void hashAppend(HASH_ALGORITHM& hashAlg, const TYPE (&input)[N]);
    // Passes the specified 'input' into the specified 'hashAlg' to be combined
    // into the internal state of the algorithm which is used to produce the
    // resulting hash value.  Note that the elements in 'input' will be hashed
    // one at a time by calling 'hashAppend' because the (template parameter)
    // 'TYPE' might not be hashable as a contiguous sequence of bytes.

}  // close package namespace

// ============================================================================
//                            INLINE DEFINITIONS
// ============================================================================

                            // ---------------------
                            // bslh::Hash_AdlWrapper
                            // ---------------------

// CREATORS
template <class HASH_ALGORITHM>
inline
bslh::Hash_AdlWrapper<HASH_ALGORITHM>::Hash_AdlWrapper()
: d_hashAlgorithm()
{}

// MANIPULATORS
template <class HASH_ALGORITHM>
inline
void bslh::Hash_AdlWrapper<HASH_ALGORITHM>::operator()(const void *input,
                                                       size_t      numBytes)
{
    d_hashAlgorithm(input, numBytes);
}

template <class HASH_ALGORITHM>
template <class ELEMENT_TYPE>
inline
void bslh::Hash_AdlWrapper<HASH_ALGORITHM>::operator()(
                                                  const ELEMENT_TYPE *input,
                                                  size_t              numBytes)
{
    d_hashAlgorithm(input, numBytes);
}

template <class HASH_ALGORITHM>
inline
typename bslh::Hash_AdlWrapper<HASH_ALGORITHM>::result_type
bslh::Hash_AdlWrapper<HASH_ALGORITHM>::computeHash()
{
    return d_hashAlgorithm.computeHash();
}

                                // ----------
                                // bslh::Hash
                                // ----------

// ACCESSORS
template <class HASH_ALGORITHM>
template <class TYPE>
inline
typename bslh::Hash<HASH_ALGORITHM>::result_type
bslh::Hash<HASH_ALGORITHM>::operator()(TYPE const& key) const
{
    Hash_AdlWrapper<HASH_ALGORITHM> wrapper;

    hashAppend(wrapper, key);
    return static_cast<result_type>(wrapper.computeHash());
}

template <>
template <class TYPE>
inline
typename bslh::Hash<bslh::DefaultHashAlgorithm>::result_type
bslh::Hash<bslh::DefaultHashAlgorithm>::operator()(TYPE const& key) const
{
    DefaultHashAlgorithm hashAlg;

    hashAppend(hashAlg, key);
    return static_cast<result_type>(hashAlg.computeHash());
}

                              // --------------
                              // FREE FUNCTIONS
                              // --------------

// FREE FUNCTIONS
template <class HASH_ALGORITHM, class TYPE>
inline
typename bsl::enable_if< bsl::is_same<TYPE, bool>::value >::type
bslh::hashAppend(HASH_ALGORITHM& hashAlg, TYPE input)
{
    // We need to ensure that any inputs that compare equal produce the same
    // hash.  Any non-zero binary representation of 'input' can be 'true', so
    // we need to normalize 'input' to ensure that we do not pass two different
    // binary representations of 'true' true into our hashing algorithm.

    unsigned char normalizedData = !!input;

    hashAlg(static_cast<void *>(&normalizedData), sizeof(normalizedData));
}

template <class HASH_ALGORITHM, class TYPE>
inline
typename bsl::enable_if< bsl::is_same<TYPE, long double>::value >::type
bslh::hashAppend(HASH_ALGORITHM& hashAlg, TYPE input)
{
    if (input == 0.0l){
        input = 0;
    }

#if (defined BSLS_PLATFORM_CPU_X86 || defined BSLS_PLATFORM_CPU_X86_64) &&    \
    (defined BSLS_PLATFORM_CMP_GNU || defined BSLS_PLATFORM_CMP_CLANG)
    // This needs to be done to work around issues when compiling with GCC and
    // Clang on 86 machines.  On 64-bit hardware, 'sizeof(long double)' is
    // advertised as 16 bytes, but only 10 bytes of precision is used.  The
    // remaining 6 bytes are padding.
    //
    // For Clang, the final 2 bytes of the padding are zeroed, but the 4 bytes
    // that proceed the final two appear to be garbage.
    //
    //..
    //      Actual Data --+*****************************+
    //                    |                             |
    // Actual long double: 5d e9 79 a9 c2 82 bb ef 2b 40 87 d8 5c 2b  0  0
    //                                                   |          ||   |
    //      Garbage -------------------------------------+**********+|   |
    //      Zeroed --------------------------------------------------+***+
    //..
    //
    // For GCC, the first and last 2 bytes of the padding are zeroed, but the 2
    // bytes in the middle appear to be garbage.
    //
    //..
    //      Garbage -------------------------------------------+****+
    //      Actual Data --+*****************************+     |     |
    //                    |                             |     |     |
    // Actual long double: 5d e9 79 a9 c2 82 bb ef 2b 40  0  0 5c 2b  0  0
    //                                                   |    |      |    |
    //      Zeroed --------------------------------------+****+------+****+
    //..
    //
    // On 32-bit hardware, 'sizeof(long double)' is advertised as 12 bytes, but
    // again, only 10 bytes of precision is used.  The remaining 2 bytes are
    // padding.
    //
    // For Clang, the 2 bytes of the padding appear to be garbage.
    //
    //..
    //      Actual Data --+*****************************+
    //                    |                             |
    // Actual long double: 5d e9 79 a9 c2 82 bb ef 2b 40 87 d8
    //                                                   |    |
    //      Garbage -------------------------------------+****+
    //..
    //
    // For GCC, the 2 bytes of the padding are zeroed.
    //
    //..
    //      Actual Data --+*****************************+
    //                    |                             |
    // Actual long double: 5d e9 79 a9 c2 82 bb ef 2b 40  0  0
    //                                                   |    |
    //      Zeroed --------------------------------------+****+
    //..
    //
    // To address all of these issues, we will pass in only 10 bytes for a
    // 'long double' even if it is longer.
  #if !defined(BSLS_PLATFORM_CMP_CLANG) && BSLS_PLATFORM_CPU_X86_64
    // We cant just check 'defined(BSLS_PLATFORM_CMP_GNU)' because Clang
    // masquerades as GCC.  Since we know that to be in this block we must be
    // using GCC or Clang, we can just check
    // '!defined(BSLS_PLATFORM_CMP_CLANG)' to get the same result.

    if (bsl::is_same<long double, __float128>::value) {
        // We need to handle the posibility that somebody has set the GCC
        // compiler flag that makes 'long double' actually be 128-bit.
        hashAlg(&input, sizeof(input));
        return;                                                       // RETURN
    }
  #endif
    hashAlg(&input, sizeof(input) > 10 ? 10 : sizeof(input));
#else
    hashAlg(&input, sizeof(input));
#endif
}

template <class HASH_ALGORITHM, size_t N>
inline
void bslh::hashAppend(HASH_ALGORITHM& hashAlg, char (&input)[N])
{
    hashAlg(&input, sizeof(char)*N);
}

template <class HASH_ALGORITHM, size_t N>
inline
void bslh::hashAppend(HASH_ALGORITHM& hashAlg, const char (&input)[N])
{
    hashAlg(&input, sizeof(char)*N);
}

template <class HASH_ALGORITHM, class TYPE, size_t N>
inline
void bslh::hashAppend(HASH_ALGORITHM& hashAlg, TYPE (&input)[N])
{

    for (size_t i = 0; i < N; ++i) {
        hashAppend(hashAlg, input[i]);
    }
}


template <class HASH_ALGORITHM, class TYPE, size_t N>
inline
void bslh::hashAppend(HASH_ALGORITHM& hashAlg, const TYPE (&input)[N])
{
    for (size_t i = 0; i < N; ++i) {
        hashAppend(hashAlg, input[i]);
    }
}

// ============================================================================
//                                TYPE TRAITS
// ============================================================================

// Type traits for STL 'hash'
//: o 'bsl::hash<TYPE>' is trivially default constructible.
//: o 'bsl::hash<TYPE>' is trivially copyable.
//: o 'bsl::hash<TYPE>' is bitwise movable.

namespace bslmf {
template <class TYPE>
struct IsBitwiseMoveable<bslh::Hash<TYPE> >
    : bsl::true_type {};
}  // close namespace bslmf


}  // close enterprise namespace

namespace bsl {
template <class TYPE>
struct is_trivially_default_constructible< ::BloombergLP::bslh::Hash<TYPE> >
: bsl::true_type
{};

template <class TYPE>
struct is_trivially_copyable< ::BloombergLP::bslh::Hash<TYPE> >
: bsl::true_type
{};
}  // close namespace bsl



#endif

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