// bslstl_hash.h                                                      -*-C++-*-
#ifndef INCLUDED_BSLSTL_HASH
#define INCLUDED_BSLSTL_HASH

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

//@PURPOSE: Provide a namespace for hash functions.
//
//@CLASSES:
//  bsl::hash: hash function for fundamental types
//
//@CANONICAL_HEADER: bsl_functional.h
//
//@SEE_ALSO: package bos+stdhdrs in the bos package group
//
//@DESCRIPTION: This component provides a template unary functor, 'bsl::hash',
// implementing the 'std::hash' functor.  'bsl::hash' applies a C++ standard
// compliant, implementation defined, hash function to fundamental types
// returning the result of such application.
//
///Standard Hash Function
///----------------------
// According to the C++ standard the requirements of a standard hash function
// 'h' are:
//
//: 1 Return a 'size_t' value between 0 and
//:   'numeric_limits<std::size_t>::max()'.
//:
//: 2 The value returned must depend only on the argument 'k'.  For multiple
//:   evaluations with the same argument 'k', the value returned must be
//:   always the same.
//:
//: 3 The function should not modify its argument.
//
///Usage
///-----
// This section illustrates intended usage of this component.
//
///Example 1: Creating and Using a Hash Cross Reference
/// - - - - - - - - - - - - - - - - - - - - - - - - - -
// Suppose we already have an array of unique values of type 'TYPE', for which
// 'operator==' is defined, and we want to be able to quickly look up whether
// an element is in the array, without exhaustively applying 'operator==' to
// all the elements in sequence.  The array itself is guaranteed not to change
// for the duration of our interest in it.
//
// The problem is much simpler than building a general-purpose hash table,
// because we know how many elements our cross reference will contain in
// advance, so we will never have to dynamically grow the number of 'buckets'.
// We do not need to copy the values into our own area, so we don't have to
// create storage for them, or require that a copy constructor or destructor be
// available.  We only require that they have a transitive, symmetric
// equivalence operation 'bool operator==' and that a hash function be
// provided.
//
// We will need a hash function -- the hash function is a function that will
// take as input an object of the type stored in our array, and yield a
// 'size_t' value that will be very randomized.  Ideally, the slightest change
// in the value of the 'TYPE' object will result in a large change in the value
// returned by the hash function.  In a good hash function, typically half the
// bits of the return value will change for a 1-bit change in the hashed value.
// We then use the result of the hash function to index into our array of
// 'buckets'.  Each 'bucket' is simply a pointer to a value in our original
// array of 'TYPE' objects.  We will resolve hash collisions in our array
// through 'linear probing', where we will search consecutive buckets following
// the bucket where the collision occurred, testing occupied buckets for
// equality with the value we are searching on, and concluding that the value
// is not in the table if we encounter an empty bucket before we encounter one
// referring to an equal element.
//
// An important quality of the hash function is that if two values are
// equivalent, they must yield the same hash value.
//
// First, we define our 'HashCrossReference' template class, with the two type
// parameters 'TYPE" (the type being referenced' and 'HASHER', which defaults
// to 'bsl::hash<TYPE>'.  For common types of 'TYPE' such as 'int', a
// specialization of 'bsl::hash' is already defined:
//..
//  template <class TYPE, class HASHER = bsl::hash<TYPE> >
//  class HashCrossReference {
//      // This table leverages a hash table to provide a fast lookup of an
//      // external, non-owned, array of values of configurable type.
//      //
//      // The only requirement for 'TYPE' is that it have a transitive,
//      // symmetric 'operator==' function.  There is no requirement that it
//      // have any kind of creator defined.
//      //
//      // The 'HASHER' template parameter type must be a functor with a
//      // function of the following signature:
//      //..
//      //  size_t operator()(const TYPE)  const; or
//      //  size_t operator()(const TYPE&) const; or
//      //..
//      // and 'HASHER' must have a publicly available default constructor and
//      // destructor.
//
//      // DATA
//      const TYPE       *d_values;             // Array of values table is to
//                                              // cross-reference.  Held, not
//                                              // owned.
//      size_t            d_numValues;          // Length of 'd_values'.
//      const TYPE      **d_bucketArray;        // Contains pointers into
//                                              // 'd_values'.
//      size_t            d_bucketArrayMask;    // Will always be '2^N - 1'.
//      HASHER            d_hasher;
//      bool              d_valid;              // Object was properly
//                                              // initialized.
//      bslma::Allocator *d_allocator_p;        // Held, not owned.
//
//    private:
//      // PRIVATE ACCESSORS
//      bool lookup(size_t      *index,
//                  const TYPE&  value,
//                  size_t       hashValue) const
//          // Look up the specified 'value', having hash value 'hashValue',
//          // and return its index in 'd_bucketArray' stored in the specified
//          // 'index'.  If not found, return the vacant entry in
//          // 'd_bucketArray' where it should be inserted.  Return 'true' if
//          // 'value' is found and 'false' otherwise.
//      {
//          const TYPE *ptr;
//          for (*index = hashValue & d_bucketArrayMask;
//               static_cast<bool>(ptr = d_bucketArray[*index]);
//               *index = (*index + 1) & d_bucketArrayMask) {
//              if (value == *ptr) {
//                  return true;                                      // RETURN
//              }
//          }
//          // value was not found in table
//
//          return false;
//      }
//
//      // NOT IMPLEMENTED
//      HashCrossReference(const HashCrossReference&);
//      HashCrossReference& operator=(const HashCrossReference&);
//
//    public:
//      // CREATORS
//      HashCrossReference(const TYPE       *valuesArray,
//                         size_t            numValues,
//                         bslma::Allocator *basicAllocator = 0)
//          // Create a hash table refering to the specified 'valuesArray'
//          // containing the specified 'numValues' elements.  Optionally
//          // specify 'basicAllocator' or the default allocator will be used.
//      : d_values(valuesArray)
//      , d_numValues(numValues)
//      , d_hasher()
//      , d_valid(true)
//      , d_allocator_p(bslma::Default::allocator(allocator))
//      {
//          size_t bucketArrayLength = 4;
//          while (bucketArrayLength < numValues * 4) {
//              bucketArrayLength *= 2;
//              BSLS_ASSERT_OPT(bucketArrayLength);
//          }
//          d_bucketArrayMask = bucketArrayLength - 1;
//          d_bucketArray = (const TYPE **) d_allocator_p->allocate(
//                                        bucketArrayLength * sizeof(TYPE **));
//          memset(d_bucketArray,  0, bucketArrayLength * sizeof(TYPE *));
//
//          for (unsigned i = 0; i < numValues; ++i) {
//              const TYPE& value = d_values[i];
//
//              size_t idx;
//              if (lookup(&idx, value, d_hasher(value))) {
//                  // Duplicate value.  Fail.
//
//                  printf("Error: entries %u and %u have the same value\n",
//                                 i, unsigned(d_bucketArray[idx] - d_values));
//                  d_valid = false;
//
//                  // don't return, continue reporting other redundant
//                  // entries.
//              }
//              else {
//                  d_bucketArray[idx] = &d_values[i];
//              }
//          }
//      }
//
//      ~HashCrossReference()
//          // Free up memory used by this cross-reference.
//      {
//          d_allocator_p->deallocate(d_bucketArray);
//      }
//
//      // ACCESSORS
//      int count(const TYPE& value) const
//          // Return 1 if the specified 'value' is found in the cross
//          // reference and 0 otherwise.
//      {
//          BSLS_ASSERT_OPT(d_valid);
//
//          size_t idx;
//          return lookup(&idx, value, d_hasher(value));
//      }
//
//      bool isValid() const
//          // Return 'true' if this cross reference was successfully
//          // constructed and 'false' otherwise.
//      {
//          return d_valid;
//      }
//  };
//..
// Then, In 'main', we will first use our cross-reference to cross-reference a
// collection of integer values.  We define our array and take its length:
//..
//  const int ints[] = { 23, 42, 47, 56, 57, 61, 62, 63, 70, 72, 79 };
//  enum { NUM_INTS = sizeof ints / sizeof *ints };
//..
// Now, we create our cross-reference 'hcri' and verify it constructed
// properly.  Note that we don't specify the second template parameter 'HASHER'
// and let it default to 'bsl::hash<int>', which is already defined by
// bslstl_hash:
//..
//  HashCrossReference<int> hcri(ints, NUM_INTS);
//  assert(hcri.isValid());
//..
// Finally, we use 'hcri' to verify numbers that were and were not in the
// collection:
//..
//  assert(1 == hcri.count(23));
//  assert(1 == hcri.count(42));
//  assert(1 == hcri.count(47));
//  assert(1 == hcri.count(56));
//  assert(0 == hcri.count( 3));
//  assert(0 == hcri.count(31));
//  assert(0 == hcri.count(37));
//  assert(0 == hcri.count(58));
//..
//
///Example 2: Using 'hashAppend' from 'bslh' with 'HashCrossReference'
///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// We want to specialize 'bsl::hash' for a custom class.  We can use the
// modular hashing system implemented in 'bslh' rather than explicitly
// specializing 'bsl::hash'.  We will re-use the 'HashCrossReference' template
// class defined in Example 1.
//
// First, we declare '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 a lot, so we
//                             // cache it rather than recalculating every
//                             // time.
//
//    public:
//      Point (int x, int y);
//          // Create a 'Point' with the specified 'x' and 'y' coordinates
//
//      double distanceToOrigin();
//          // Return the distance from the origin (0, 0) to this point.
//
//..
// Then, we declare 'operator==' as a friend so that we will be able to compare
// two points.
//..
//      friend bool operator==(const Point &left, const Point &right);
//
//..
// Next, we declare 'hashAppend' as a friend so that we will be able hash a
// 'Point'.
//..
//      template <class HASH_ALGORITHM>
//      friend
//      void hashAppend(HASH_ALGORITHM &hashAlg, const Point &point);
//          // Apply the specified 'hashAlg' to the specified 'point'
//  };
//
//  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);
//  }
//
//  double Point::distanceToOrigin()
//  {
//      return d_distToOrigin;
//  }
//
//..
// Then, we define 'operator=='.  Notice how it only checks salient attributes
// - attributes that contribute to the value of the class.  We ignore
// 'd_distToOrigin' which is not required to determine equality.
//..
//  bool operator==(const Point &left, const Point &right)
//  {
//      return (left.d_x == right.d_x) && (left.d_y == right.d_y);
//  }
//
//..
// Next, we define 'hashAppend'.  This method will allow any hashing algorithm
// to be applied to 'Point'.  This is the 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 salient attributes (which have already been
// determined by 'operator==') by calling 'hashAppend' on them.
//..
//  template <class HASH_ALGORITHM>
//  void hashAppend(HASH_ALGORITHM &hashAlg, const Point &point)
//  {
//      using ::BloombergLP::bslh::hashAppend;
//      hashAppend(hashAlg, point.d_x);
//      hashAppend(hashAlg, point.d_y);
//  }
//
//..
// Then, we declare another value-semantic type, 'Box', that has a 'Point' as
// one of its salient attributes.
//..
//  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 with the specified 'length' and 'width', with its
//          // upper left corner at the specified 'position'
//
//..
// Next, we declare 'operator==' and 'hashAppend' as we did before.
//..
//      friend bool operator==(const Box &left, const Box &right);
//
//      template <class HASH_ALGORITHM>
//      friend
//      void hashAppend(HASH_ALGORITHM &hashAlg, const Box &box);
//          // Apply the specified 'hashAlg' to the specified 'box'
//  };
//
//  Box::Box(Point position, int length, int width) : d_position(position),
//                                                    d_length(length),
//                                                    d_width(width) { }
//
//..
// Then, we define 'operator=='.  This time all of the data members contribute
// to equality.
//..
//  bool operator==(const Box &left, const Box &right)
//  {
//      return (left.d_position == right.d_position) &&
//             (left.d_length   == right.d_length) &&
//             (left.d_width    == right.d_width);
//  }
//
//..
// Next, we define 'hashAppend' for 'Box'.  Notice how as well as calling
// 'hashAppend' on fundamental types, we can also call it on our user-defined
// type 'Point'.  Calling 'hashAppend' on 'Point' will propagate the hashing
// algorithm functor 'hashAlg' down to the fundamental types that make up
// 'Point', and those types will then be passed into the algorithm functor.
//..
//  template <class HASH_ALGORITHM>
//  void hashAppend(HASH_ALGORITHM &hashAlg, const Box &box)
//  {
//      hashAppend(hashAlg, box.d_position);
//      hashAppend(hashAlg, box.d_length);
//      hashAppend(hashAlg, box.d_width);
//  }
//..
// Then, we want to use our cross reference on a 'Box'.  We create an array of
// unique 'Box's and take its length:
//..
//
//      Box boxes[] = { Box(Point(0, 0), 2, 3),
//                      Box(Point(1, 0), 1, 1),
//                      Box(Point(0, 1), 1, 5),
//                      Box(Point(1, 1), 5, 6),
//                      Box(Point(2, 1), 1, 13),
//                      Box(Point(0, 4), 3, 3),
//                      Box(Point(3, 2), 2, 17) };
//      enum { NUM_BOXES = sizeof boxes / sizeof *boxes };
//
//..
// Next, we create our cross-reference 'hcrsts' and verify that it constructed
// properly.  Note we don't pass a second parameter template argument and let
// 'HASHER' default to 'bsl::hash<TYPE>'.  Since we have not specialized
// 'bsl::hash' for 'Box', 'bsl::hash<TYPE>' will attempt to use 'bslh::hash<>'
// to hash 'Box'.
//..
//
//      HashCrossReference<Box> hcrsts(boxes, NUM_BOXES);
//      ASSERT(hcrsts.isValid());
//
//..
// Now, we verify that each element in our array registers with count:
//..
//      for(int i = 0; i < NUM_BOXES; ++i) {
//          ASSERT(1 == hcrsts.count(boxes[i]));
//      }
//
//..
// Finally, we verify that elements not in our original array are correctly
// identified as not being in the set:
//..
//      ASSERT(0 == hcrsts.count(Box(Point(3, 3), 3, 3)));
//      ASSERT(0 == hcrsts.count(Box(Point(3, 2), 1, 0)));
//      ASSERT(0 == hcrsts.count(Box(Point(1, 2), 3, 4)));
//      ASSERT(0 == hcrsts.count(Box(Point(33, 23), 13, 3)));
//      ASSERT(0 == hcrsts.count(Box(Point(30, 37), 34, 13)));
//..

#include <bslscm_version.h>

#include <bslh_hash.h>

#include <bslmf_istriviallycopyable.h>
#include <bslmf_istriviallydefaultconstructible.h>
#include <bslmf_assert.h>

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

#include <cstddef>  // for 'std::size_t'

#define BSLSTL_HASH_DEPRECATED_CPP17                                          \
    BSLS_DEPRECATE_FEATURE(                                                   \
        "bsl", "deprecated_cpp17_standard_library_features", "do not use")

namespace bsl {

                          // ==================
                          // class bslstl::hash
                          // ==================

template <class TYPE>
struct hash : ::BloombergLP::bslh::Hash<> {
    // Empty base class for hashing.  This class, and all explicit and partial
    // specializations of this class, shall conform to the C++11 Hash
    // Requirements (C++11 17.6.3.4, [hash.requirements]).  Unless this
    // template is explicitly specialized, it will use the default hash
    // algorithm provided by 'bslh::Hash<>' to supply hash values.  In order to
    // hash a user-defined type using 'bsl::hash', 'bsl::hash' must be
    // explicitly specialized for the type, or, preferably, 'hashAppend' must
    // be implemented for the type.  For more details on 'hashAppend' and
    // 'bslh::Hash' see the component 'bslh_hash'.

    // PUBLIC ACCESSORS
    std::size_t operator()(const TYPE &value) const;
        // Compute and return the hash of the specified 'value'.  This
        // implementation forwards to the call operator of the base class, but
        // with the parameter guaranteed to be of type 'TYPE'.
};

// ============================================================================
//                  SPECIALIZATIONS FOR FUNDAMENTAL TYPES
// ============================================================================

template <class BSLSTL_KEY>
struct hash<const BSLSTL_KEY> : hash<BSLSTL_KEY> {
    // This class provides hashing functionality for constant key types, by
    // delegating to the same function for non-constant key types.
};

template <>
struct hash<bool> {
    // Specialization of 'hash' for 'bool' values.

    // STANDARD TYPEDEFS
    BSLSTL_HASH_DEPRECATED_CPP17
    typedef bool argument_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    BSLSTL_HASH_DEPRECATED_CPP17
    typedef std::size_t result_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    //! hash() = default;
        // Create a 'hash' object.

    //! hash(const hash& original) = default;
        // Create a 'hash' object.  Note that as 'hash' is an empty (stateless)
        // type, this operation has 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 'hash' is an empty (stateless) type, this operation has no
        // observable effect.

    // ACCESSORS
    std::size_t operator()(bool x) const;
        // Return a hash value computed using the specified 'x'.
};

template <>
struct hash<char> {
    // Specialization of 'hash' for 'char' values.

    // STANDARD TYPEDEFS
    BSLSTL_HASH_DEPRECATED_CPP17
    typedef char argument_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    BSLSTL_HASH_DEPRECATED_CPP17
    typedef std::size_t result_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    //! hash() = default;
        // Create a 'hash' object.

    //! hash(const hash& original) = default;
        // Create a 'hash' object.  Note that as 'hash' is an empty (stateless)
        // type, this operation has 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 'hash' is an empty (stateless) type, this operation has no
        // observable effect.

    // ACCESSORS
    std::size_t operator()(char x) const;
        // Return a hash value computed using the specified 'x'.
};

template <>
struct hash<signed char> {
    // Specialization of 'hash' for 'signed' 'char' values.

    // STANDARD TYPEDEFS
    BSLSTL_HASH_DEPRECATED_CPP17
    typedef signed char argument_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    BSLSTL_HASH_DEPRECATED_CPP17
    typedef std::size_t result_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    //! hash() = default;
        // Create a 'hash' object.

    //! hash(const hash& original) = default;
        // Create a 'hash' object.  Note that as 'hash' is an empty (stateless)
        // type, this operation has 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 'hash' is an empty (stateless) type, this operation has no
        // observable effect.

    // ACCESSORS
    std::size_t operator()(signed char x) const;
        // Return a hash value computed using the specified 'x'.
};

template <>
struct hash<unsigned char> {
    // Specialization of 'hash' for 'unsigned' 'char' values.

    // STANDARD TYPEDEFS
    BSLSTL_HASH_DEPRECATED_CPP17
    typedef unsigned char argument_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    BSLSTL_HASH_DEPRECATED_CPP17
    typedef std::size_t result_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    //! hash() = default;
        // Create a 'hash' object.

    //! hash(const hash& original) = default;
        // Create a 'hash' object.  Note that as 'hash' is an empty (stateless)
        // type, this operation has 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 'hash' is an empty (stateless) type, this operation has no
        // observable effect.

    // ACCESSORS
    std::size_t operator()(unsigned char x) const;
        // Return a hash value computed using the specified 'x'.
};

template <>
struct hash<wchar_t> {
    // Specialization of 'hash' for 'wchar_t' values.

    // STANDARD TYPEDEFS
    BSLSTL_HASH_DEPRECATED_CPP17
    typedef wchar_t argument_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    BSLSTL_HASH_DEPRECATED_CPP17
    typedef std::size_t result_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    //! hash() = default;
        // Create a 'hash' object.

    //! hash(const hash& original) = default;
        // Create a 'hash' object.  Note that as 'hash' is an empty (stateless)
        // type, this operation has 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 'hash' is an empty (stateless) type, this operation has no
        // observable effect.

    // ACCESSORS
    std::size_t operator()(wchar_t x) const;
        // Return a hash value computed using the specified 'x'.
};

template <>
struct hash<short> {
    // Specialization of 'hash' for 'short' values.

    // STANDARD TYPEDEFS
    BSLSTL_HASH_DEPRECATED_CPP17
    typedef short argument_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    BSLSTL_HASH_DEPRECATED_CPP17
    typedef std::size_t result_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    //! hash() = default;
        // Create a 'hash' object.

    //! hash(const hash& original) = default;
        // Create a 'hash' object.  Note that as 'hash' is an empty (stateless)
        // type, this operation has 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 'hash' is an empty (stateless) type, this operation has no
        // observable effect.

    // ACCESSORS
    std::size_t operator()(short x) const;
        // Return a hash value computed using the specified 'x'.
};

template <>
struct hash<unsigned short> {
    // Specialization of 'hash' for 'unsigned' 'short' values.

    // STANDARD TYPEDEFS
    BSLSTL_HASH_DEPRECATED_CPP17
    typedef unsigned short argument_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    BSLSTL_HASH_DEPRECATED_CPP17
    typedef std::size_t result_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    //! hash() = default;
        // Create a 'hash' object.

    //! hash(const hash& original) = default;
        // Create a 'hash' object.  Note that as 'hash' is an empty (stateless)
        // type, this operation has 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 'hash' is an empty (stateless) type, this operation has no
        // observable effect.

    // ACCESSORS
    std::size_t operator()(unsigned short x) const;
        // Return a hash value computed using the specified 'x'.
};

template <>
struct hash<int> {
    // Specialization of 'hash' for 'int' values.

    // STANDARD TYPEDEFS
    BSLSTL_HASH_DEPRECATED_CPP17
    typedef int argument_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    BSLSTL_HASH_DEPRECATED_CPP17
    typedef std::size_t result_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    //! hash() = default;
        // Create a 'hash' object.

    //! hash(const hash& original) = default;
        // Create a 'hash' object.  Note that as 'hash' is an empty (stateless)
        // type, this operation has 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 'hash' is an empty (stateless) type, this operation has no
        // observable effect.

    // ACCESSORS
    std::size_t operator()(int x) const;
        // Return a hash value computed using the specified 'x'.
};

template <>
struct hash<unsigned int> {
    // Specialization of 'hash' for 'unsigned' 'int' values.

    // STANDARD TYPEDEFS
    BSLSTL_HASH_DEPRECATED_CPP17
    typedef unsigned int argument_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    BSLSTL_HASH_DEPRECATED_CPP17
    typedef std::size_t result_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    //! hash() = default;
        // Create a 'hash' object.

    //! hash(const hash& original) = default;
        // Create a 'hash' object.  Note that as 'hash' is an empty (stateless)
        // type, this operation has 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 'hash' is an empty (stateless) type, this operation has no
        // observable effect.

    // ACCESSORS
    std::size_t operator()(unsigned int x) const;
        // Return a hash value computed using the specified 'x'.
};

template <>
struct hash<long> {
    // Specialization of 'hash' for 'long' values.

    // STANDARD TYPEDEFS
    BSLSTL_HASH_DEPRECATED_CPP17
    typedef long argument_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    BSLSTL_HASH_DEPRECATED_CPP17
    typedef std::size_t result_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    //! hash() = default;
        // Create a 'hash' object.

    //! hash(const hash& original) = default;
        // Create a 'hash' object.  Note that as 'hash' is an empty (stateless)
        // type, this operation has 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 'hash' is an empty (stateless) type, this operation has no
        // observable effect.

    // ACCESSORS
    std::size_t operator()(long x) const;
        // Return a hash value computed using the specified 'x'.
};

template <>
struct hash<unsigned long> {
    // Specialization of 'hash' for 'unsigned' 'long' values.

    // STANDARD TYPEDEFS
    BSLSTL_HASH_DEPRECATED_CPP17
    typedef unsigned long argument_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    BSLSTL_HASH_DEPRECATED_CPP17
    typedef std::size_t result_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    //! hash() = default;
        // Create a 'hash' object.

    //! hash(const hash& original) = default;
        // Create a 'hash' object.  Note that as 'hash' is an empty (stateless)
        // type, this operation has 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 'hash' is an empty (stateless) type, this operation has no
        // observable effect.

    // ACCESSORS
    std::size_t operator()(unsigned long x) const;
        // Return a hash value computed using the specified 'x'.
};

template <>
struct hash<long long> {
    // Specialization of 'hash' for 'long long' values.

    // STANDARD TYPEDEFS
    BSLSTL_HASH_DEPRECATED_CPP17
    typedef long long argument_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    BSLSTL_HASH_DEPRECATED_CPP17
    typedef std::size_t result_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    //! hash() = default;
        // Create a 'hash' object.

    //! hash(const hash& original) = default;
        // Create a 'hash' object.  Note that as 'hash' is an empty (stateless)
        // type, this operation has 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 'hash' is an empty (stateless) type, this operation has no
        // observable effect.

    // ACCESSORS
    std::size_t operator()(long long x) const;
        // Return a hash value computed using the specified 'x'.
};

template <>
struct hash<unsigned long long> {
    // Specialization of 'hash' for 'unsigned' 'long long' values.

    // STANDARD TYPEDEFS
    BSLSTL_HASH_DEPRECATED_CPP17
    typedef unsigned long long argument_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    BSLSTL_HASH_DEPRECATED_CPP17
    typedef std::size_t result_type;
        // !DEPRECATED!: This typedef is depreacted in C++17, for details see
        // https://isocpp.org/files/papers/p0005r4.html.

    //! hash() = default;
        // Create a 'hash' object.

    //! hash(const hash& original) = default;
        // Create a 'hash' object.  Note that as 'hash' is an empty (stateless)
        // type, this operation has 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 'hash' is an empty (stateless) type, this operation has no
        // observable effect.

    // ACCESSORS
    std::size_t operator()(unsigned long long x) const;
        // Return a hash value computed using the specified 'x'.
};

// ============================================================================
//                  TEMPLATE AND INLINE FUNCTION DEFINITIONS
// ============================================================================

template <class TYPE>
inline
std::size_t hash<TYPE>::operator()(const TYPE& value) const
{
    return ::BloombergLP::bslh::Hash<>::operator()(value);
}

inline
std::size_t hash<bool>::operator()(bool x) const
{
    return x;
}

inline
std::size_t hash<char>::operator()(char x) const
{
    return x;
}

inline
std::size_t hash<signed char>::operator()(signed char x) const
{
    return x;
}

inline
std::size_t hash<unsigned char>::operator()(unsigned char x) const
{
    return x;
}

inline
std::size_t hash<wchar_t>::operator()(wchar_t x) const
{
    return x;
}

inline
std::size_t hash<short>::operator()(short x) const
{
    return x;
}

inline
std::size_t hash<unsigned short>::operator()(unsigned short x) const
{
    return x;
}

inline
std::size_t hash<int>::operator()(int x) const
{
    return x;
}

inline
std::size_t hash<unsigned int>::operator()(unsigned int x) const
{
    return x;
}

inline
std::size_t hash<long>::operator()(long x) const
{
    return x;
}

inline
std::size_t hash<unsigned long>::operator()(unsigned long x) const
{
    return x;
}


#ifdef BSLS_PLATFORM_CPU_64_BIT
inline
std::size_t hash<long long>::operator()(long long x) const
{
    BSLMF_ASSERT(sizeof (long long) == sizeof (std::size_t));
    return x;
}

inline
std::size_t hash<unsigned long long>::operator()(unsigned long long x) const
{
    BSLMF_ASSERT(sizeof (long long) == sizeof (std::size_t));
    return x;
}

#else // BSLS_PLATFORM_CPU_32_BIT

inline
std::size_t hash<long long>::operator()(long long x) const
{
    BSLMF_ASSERT(sizeof (long long) > sizeof (std::size_t));

    // The mangling algorithm won't work unless these conditions hold:

    BSLMF_ASSERT(sizeof (std::size_t) * 8 == 32);
    BSLMF_ASSERT(sizeof (long long) * 8 == 64);

    // Return a simple mangling of the 64-bits of 'x' to generate a 32-bit hash
    // value (xor the high and low 32 bits together).

    return static_cast<std::size_t>((x ^ (x >> 32)) & 0xFFFFFFFF);
}

inline
std::size_t hash<unsigned long long>::operator()(unsigned long long x) const
{
    BSLMF_ASSERT(sizeof (long long) > sizeof (std::size_t));

    // The mangling algorithm won't work unless these conditions hold:

    BSLMF_ASSERT(sizeof (std::size_t) * 8 == 32);
    BSLMF_ASSERT(sizeof (unsigned long long) * 8 == 64);

    // Return a simple mangling of the 64-bits of 'x' to generate a 32-bit hash
    // value (xor the high and low 32 bits together).

    return static_cast<std::size_t>((x ^ (x >> 32)) & 0xFFFFFFFF);
}
#endif

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

template <class TYPE>
struct is_trivially_default_constructible<hash<TYPE> >
: bsl::true_type
{};

template <class TYPE>
struct is_trivially_copyable<hash<TYPE> >
: bsl::true_type
{};

}  // close namespace bsl

#undef BSLSTL_HASH_DEPRECATED_CPP17

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