Implement P0513R0 - "Poisoning the Hash"
authorEric Fiselier <eric@efcs.ca>
Sat, 21 Jan 2017 00:02:12 +0000 (00:02 +0000)
committerEric Fiselier <eric@efcs.ca>
Sat, 21 Jan 2017 00:02:12 +0000 (00:02 +0000)
Summary:
Exactly what the title says.

This patch also adds a `std::hash<nullptr_t>` specialization in C++17, but it was not added by this paper and I can't find the actual paper that adds it.

See http://wg21.link/P0513R0 for more info.

If there are no comments in the next couple of days I'll commit this

Reviewers: mclow.lists, K-ballo, EricWF

Reviewed By: EricWF

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D28938

llvm-svn: 292684

31 files changed:
libcxx/include/__functional_base
libcxx/include/functional
libcxx/include/memory
libcxx/include/new
libcxx/include/optional
libcxx/include/utility
libcxx/include/variant
libcxx/test/libcxx/test/config.py
libcxx/test/std/containers/sequences/vector.bool/enabled_hash.pass.cpp [new file with mode: 0644]
libcxx/test/std/diagnostics/syserr/syserr.hash/enabled_hash.pass.cpp [new file with mode: 0644]
libcxx/test/std/strings/basic.string.hash/enabled_hashes.pass.cpp [new file with mode: 0644]
libcxx/test/std/strings/string.view/string.view.hash/enabled_hashes.pass.cpp [new file with mode: 0644]
libcxx/test/std/strings/string.view/string.view.hash/string_view.pass.cpp
libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/enabled_hashes.pass.cpp [new file with mode: 0644]
libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/thread_id.pass.cpp
libcxx/test/std/utilities/function.objects/unord.hash/enabled_hashes.pass.cpp [new file with mode: 0644]
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.hash/enabled_hash.pass.cpp [new file with mode: 0644]
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.hash/hash_shared_ptr.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.hash/hash_unique_ptr.pass.cpp
libcxx/test/std/utilities/optional/optional.hash/enabled_hash.pass.cpp [new file with mode: 0644]
libcxx/test/std/utilities/optional/optional.hash/hash.pass.cpp
libcxx/test/std/utilities/template.bitset/bitset.hash/enabled_hash.pass.cpp [new file with mode: 0644]
libcxx/test/std/utilities/type.index/type.index.hash/enabled_hash.pass.cpp [new file with mode: 0644]
libcxx/test/std/utilities/type.index/type.index.synopsis/hash_type_index.pass.cpp
libcxx/test/std/utilities/variant/variant.hash/enabled_hash.pass.cpp [new file with mode: 0644]
libcxx/test/std/utilities/variant/variant.hash/hash.pass.cpp
libcxx/test/support/deleter_types.h
libcxx/test/support/min_allocator.h
libcxx/test/support/poisoned_hash_helper.hpp [new file with mode: 0644]
libcxx/test/support/test.support/test_poisoned_hash_helper.pass.cpp [new file with mode: 0644]
libcxx/www/cxx1z_status.html

index 05c9f06..4e2b7eb 100644 (file)
@@ -16,6 +16,7 @@
 #include <typeinfo>
 #include <exception>
 #include <new>
+#include <utility>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-template <class _Arg, class _Result>
-struct _LIBCPP_TEMPLATE_VIS unary_function
-{
-    typedef _Arg    argument_type;
-    typedef _Result result_type;
-};
-
 template <class _Arg1, class _Arg2, class _Result>
 struct _LIBCPP_TEMPLATE_VIS binary_function
 {
index 4f8ec65..2a810b1 100644 (file)
@@ -485,6 +485,7 @@ POLICY:  For non-variadic implementations, the number of arguments is limited
 #include <exception>
 #include <memory>
 #include <tuple>
+#include <utility>
 
 #include <__functional_base>
 
@@ -2339,247 +2340,6 @@ bind(_Fp&& __f, _BoundArgs&&... __bound_args)
 
 #endif  // _LIBCPP_HAS_NO_VARIADICS
 
-template <>
-struct _LIBCPP_TEMPLATE_VIS hash<bool>
-    : public unary_function<bool, size_t>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(bool __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
-};
-
-template <>
-struct _LIBCPP_TEMPLATE_VIS hash<char>
-    : public unary_function<char, size_t>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(char __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
-};
-
-template <>
-struct _LIBCPP_TEMPLATE_VIS hash<signed char>
-    : public unary_function<signed char, size_t>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(signed char __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
-};
-
-template <>
-struct _LIBCPP_TEMPLATE_VIS hash<unsigned char>
-    : public unary_function<unsigned char, size_t>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(unsigned char __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
-};
-
-#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
-
-template <>
-struct _LIBCPP_TEMPLATE_VIS hash<char16_t>
-    : public unary_function<char16_t, size_t>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(char16_t __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
-};
-
-template <>
-struct _LIBCPP_TEMPLATE_VIS hash<char32_t>
-    : public unary_function<char32_t, size_t>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(char32_t __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
-};
-
-#endif  // _LIBCPP_HAS_NO_UNICODE_CHARS
-
-template <>
-struct _LIBCPP_TEMPLATE_VIS hash<wchar_t>
-    : public unary_function<wchar_t, size_t>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(wchar_t __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
-};
-
-template <>
-struct _LIBCPP_TEMPLATE_VIS hash<short>
-    : public unary_function<short, size_t>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(short __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
-};
-
-template <>
-struct _LIBCPP_TEMPLATE_VIS hash<unsigned short>
-    : public unary_function<unsigned short, size_t>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(unsigned short __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
-};
-
-template <>
-struct _LIBCPP_TEMPLATE_VIS hash<int>
-    : public unary_function<int, size_t>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(int __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
-};
-
-template <>
-struct _LIBCPP_TEMPLATE_VIS hash<unsigned int>
-    : public unary_function<unsigned int, size_t>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(unsigned int __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
-};
-
-template <>
-struct _LIBCPP_TEMPLATE_VIS hash<long>
-    : public unary_function<long, size_t>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(long __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
-};
-
-template <>
-struct _LIBCPP_TEMPLATE_VIS hash<unsigned long>
-    : public unary_function<unsigned long, size_t>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(unsigned long __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
-};
-
-template <>
-struct _LIBCPP_TEMPLATE_VIS hash<long long>
-    : public __scalar_hash<long long>
-{
-};
-
-template <>
-struct _LIBCPP_TEMPLATE_VIS hash<unsigned long long>
-    : public __scalar_hash<unsigned long long>
-{
-};
-
-#ifndef _LIBCPP_HAS_NO_INT128
-
-template <>
-struct _LIBCPP_TEMPLATE_VIS hash<__int128_t>
-    : public __scalar_hash<__int128_t>
-{
-};
-
-template <>
-struct _LIBCPP_TEMPLATE_VIS hash<__uint128_t>
-    : public __scalar_hash<__uint128_t>
-{
-};
-
-#endif
-
-template <>
-struct _LIBCPP_TEMPLATE_VIS hash<float>
-    : public __scalar_hash<float>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(float __v) const _NOEXCEPT
-    {
-        // -0.0 and 0.0 should return same hash
-       if (__v == 0)
-           return 0;
-        return __scalar_hash<float>::operator()(__v);
-    }
-};
-
-template <>
-struct _LIBCPP_TEMPLATE_VIS hash<double>
-    : public __scalar_hash<double>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(double __v) const _NOEXCEPT
-    {
-        // -0.0 and 0.0 should return same hash
-       if (__v == 0)
-           return 0;
-        return __scalar_hash<double>::operator()(__v);
-    }
-};
-
-template <>
-struct _LIBCPP_TEMPLATE_VIS hash<long double>
-    : public __scalar_hash<long double>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(long double __v) const _NOEXCEPT
-    {
-        // -0.0 and 0.0 should return same hash
-        if (__v == 0)
-            return 0;
-#if defined(__i386__)
-        // Zero out padding bits
-        union
-        {
-            long double __t;
-            struct
-            {
-                size_t __a;
-                size_t __b;
-                size_t __c;
-                size_t __d;
-            } __s;
-        } __u;
-        __u.__s.__a = 0;
-        __u.__s.__b = 0;
-        __u.__s.__c = 0;
-        __u.__s.__d = 0;
-        __u.__t = __v;
-        return __u.__s.__a ^ __u.__s.__b ^ __u.__s.__c ^ __u.__s.__d;
-#elif defined(__x86_64__)
-        // Zero out padding bits
-        union
-        {
-            long double __t;
-            struct
-            {
-                size_t __a;
-                size_t __b;
-            } __s;
-        } __u;
-        __u.__s.__a = 0;
-        __u.__s.__b = 0;
-        __u.__t = __v;
-        return __u.__s.__a ^ __u.__s.__b;
-#else
-        return __scalar_hash<long double>::operator()(__v);
-#endif
-    }
-};
-
-#if _LIBCPP_STD_VER > 11
-
-template <class _Tp, bool = is_enum<_Tp>::value>
-struct _LIBCPP_TEMPLATE_VIS __enum_hash
-    : public unary_function<_Tp, size_t>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(_Tp __v) const _NOEXCEPT
-    {
-        typedef typename underlying_type<_Tp>::type type;
-        return hash<type>{}(static_cast<type>(__v));
-    }
-};
-template <class _Tp>
-struct _LIBCPP_TEMPLATE_VIS __enum_hash<_Tp, false> {
-    __enum_hash() = delete;
-    __enum_hash(__enum_hash const&) = delete;
-    __enum_hash& operator=(__enum_hash const&) = delete;
-};
-
-template <class _Tp>
-struct _LIBCPP_TEMPLATE_VIS hash : public __enum_hash<_Tp>
-{
-};
-#endif
-
-
 #if _LIBCPP_STD_VER > 14
 
 #define __cpp_lib_invoke 201411
index 1b58550..f4a9383 100644 (file)
@@ -3021,360 +3021,13 @@ template<class _Tp, class... _Args>
 
 #endif  // _LIBCPP_STD_VER > 11
 
-template <class _Size>
-inline _LIBCPP_INLINE_VISIBILITY
-_Size
-__loadword(const void* __p)
-{
-    _Size __r;
-    std::memcpy(&__r, __p, sizeof(__r));
-    return __r;
-}
-
-// We use murmur2 when size_t is 32 bits, and cityhash64 when size_t
-// is 64 bits.  This is because cityhash64 uses 64bit x 64bit
-// multiplication, which can be very slow on 32-bit systems.
-template <class _Size, size_t = sizeof(_Size)*__CHAR_BIT__>
-struct __murmur2_or_cityhash;
-
-template <class _Size>
-struct __murmur2_or_cityhash<_Size, 32>
-{
-    _Size operator()(const void* __key, _Size __len);
-};
-
-// murmur2
-template <class _Size>
-_Size
-__murmur2_or_cityhash<_Size, 32>::operator()(const void* __key, _Size __len) _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK 
-{
-    const _Size __m = 0x5bd1e995;
-    const _Size __r = 24;
-    _Size __h = __len;
-    const unsigned char* __data = static_cast<const unsigned char*>(__key);
-    for (; __len >= 4; __data += 4, __len -= 4)
-    {
-        _Size __k = __loadword<_Size>(__data);
-        __k *= __m;
-        __k ^= __k >> __r;
-        __k *= __m;
-        __h *= __m;
-        __h ^= __k;
-    }
-    switch (__len)
-    {
-    case 3:
-        __h ^= __data[2] << 16;
-    case 2:
-        __h ^= __data[1] << 8;
-    case 1:
-        __h ^= __data[0];
-        __h *= __m;
-    }
-    __h ^= __h >> 13;
-    __h *= __m;
-    __h ^= __h >> 15;
-    return __h;
-}
-
-template <class _Size>
-struct __murmur2_or_cityhash<_Size, 64>
-{
-    _Size operator()(const void* __key, _Size __len);
-
- private:
-  // Some primes between 2^63 and 2^64.
-  static const _Size __k0 = 0xc3a5c85c97cb3127ULL;
-  static const _Size __k1 = 0xb492b66fbe98f273ULL;
-  static const _Size __k2 = 0x9ae16a3b2f90404fULL;
-  static const _Size __k3 = 0xc949d7c7509e6557ULL;
-
-  static _Size __rotate(_Size __val, int __shift) {
-    return __shift == 0 ? __val : ((__val >> __shift) | (__val << (64 - __shift)));
-  }
-
-  static _Size __rotate_by_at_least_1(_Size __val, int __shift) {
-    return (__val >> __shift) | (__val << (64 - __shift));
-  }
-
-  static _Size __shift_mix(_Size __val) {
-    return __val ^ (__val >> 47);
-  }
-
-  static _Size __hash_len_16(_Size __u, _Size __v) {
-    const _Size __mul = 0x9ddfea08eb382d69ULL;
-    _Size __a = (__u ^ __v) * __mul;
-    __a ^= (__a >> 47);
-    _Size __b = (__v ^ __a) * __mul;
-    __b ^= (__b >> 47);
-    __b *= __mul;
-    return __b;
-  }
-
-  static _Size __hash_len_0_to_16(const char* __s, _Size __len) {
-    if (__len > 8) {
-      const _Size __a = __loadword<_Size>(__s);
-      const _Size __b = __loadword<_Size>(__s + __len - 8);
-      return __hash_len_16(__a, __rotate_by_at_least_1(__b + __len, __len)) ^ __b;
-    }
-    if (__len >= 4) {
-      const uint32_t __a = __loadword<uint32_t>(__s);
-      const uint32_t __b = __loadword<uint32_t>(__s + __len - 4);
-      return __hash_len_16(__len + (__a << 3), __b);
-    }
-    if (__len > 0) {
-      const unsigned char __a = __s[0];
-      const unsigned char __b = __s[__len >> 1];
-      const unsigned char __c = __s[__len - 1];
-      const uint32_t __y = static_cast<uint32_t>(__a) +
-                           (static_cast<uint32_t>(__b) << 8);
-      const uint32_t __z = __len + (static_cast<uint32_t>(__c) << 2);
-      return __shift_mix(__y * __k2 ^ __z * __k3) * __k2;
-    }
-    return __k2;
-  }
-
-  static _Size __hash_len_17_to_32(const char *__s, _Size __len) {
-    const _Size __a = __loadword<_Size>(__s) * __k1;
-    const _Size __b = __loadword<_Size>(__s + 8);
-    const _Size __c = __loadword<_Size>(__s + __len - 8) * __k2;
-    const _Size __d = __loadword<_Size>(__s + __len - 16) * __k0;
-    return __hash_len_16(__rotate(__a - __b, 43) + __rotate(__c, 30) + __d,
-                         __a + __rotate(__b ^ __k3, 20) - __c + __len);
-  }
-
-  // Return a 16-byte hash for 48 bytes.  Quick and dirty.
-  // Callers do best to use "random-looking" values for a and b.
-  static pair<_Size, _Size> __weak_hash_len_32_with_seeds(
-      _Size __w, _Size __x, _Size __y, _Size __z, _Size __a, _Size __b) {
-    __a += __w;
-    __b = __rotate(__b + __a + __z, 21);
-    const _Size __c = __a;
-    __a += __x;
-    __a += __y;
-    __b += __rotate(__a, 44);
-    return pair<_Size, _Size>(__a + __z, __b + __c);
-  }
-
-  // Return a 16-byte hash for s[0] ... s[31], a, and b.  Quick and dirty.
-  static pair<_Size, _Size> __weak_hash_len_32_with_seeds(
-      const char* __s, _Size __a, _Size __b) {
-    return __weak_hash_len_32_with_seeds(__loadword<_Size>(__s),
-                                         __loadword<_Size>(__s + 8),
-                                         __loadword<_Size>(__s + 16),
-                                         __loadword<_Size>(__s + 24),
-                                         __a,
-                                         __b);
-  }
-
-  // Return an 8-byte hash for 33 to 64 bytes.
-  static _Size __hash_len_33_to_64(const char *__s, size_t __len) {
-    _Size __z = __loadword<_Size>(__s + 24);
-    _Size __a = __loadword<_Size>(__s) +
-                (__len + __loadword<_Size>(__s + __len - 16)) * __k0;
-    _Size __b = __rotate(__a + __z, 52);
-    _Size __c = __rotate(__a, 37);
-    __a += __loadword<_Size>(__s + 8);
-    __c += __rotate(__a, 7);
-    __a += __loadword<_Size>(__s + 16);
-    _Size __vf = __a + __z;
-    _Size __vs = __b + __rotate(__a, 31) + __c;
-    __a = __loadword<_Size>(__s + 16) + __loadword<_Size>(__s + __len - 32);
-    __z += __loadword<_Size>(__s + __len - 8);
-    __b = __rotate(__a + __z, 52);
-    __c = __rotate(__a, 37);
-    __a += __loadword<_Size>(__s + __len - 24);
-    __c += __rotate(__a, 7);
-    __a += __loadword<_Size>(__s + __len - 16);
-    _Size __wf = __a + __z;
-    _Size __ws = __b + __rotate(__a, 31) + __c;
-    _Size __r = __shift_mix((__vf + __ws) * __k2 + (__wf + __vs) * __k0);
-    return __shift_mix(__r * __k0 + __vs) * __k2;
-  }
-};
-
-// cityhash64
-template <class _Size>
-_Size
-__murmur2_or_cityhash<_Size, 64>::operator()(const void* __key, _Size __len) _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK 
-{
-  const char* __s = static_cast<const char*>(__key);
-  if (__len <= 32) {
-    if (__len <= 16) {
-      return __hash_len_0_to_16(__s, __len);
-    } else {
-      return __hash_len_17_to_32(__s, __len);
-    }
-  } else if (__len <= 64) {
-    return __hash_len_33_to_64(__s, __len);
-  }
-
-  // For strings over 64 bytes we hash the end first, and then as we
-  // loop we keep 56 bytes of state: v, w, x, y, and z.
-  _Size __x = __loadword<_Size>(__s + __len - 40);
-  _Size __y = __loadword<_Size>(__s + __len - 16) +
-              __loadword<_Size>(__s + __len - 56);
-  _Size __z = __hash_len_16(__loadword<_Size>(__s + __len - 48) + __len,
-                          __loadword<_Size>(__s + __len - 24));
-  pair<_Size, _Size> __v = __weak_hash_len_32_with_seeds(__s + __len - 64, __len, __z);
-  pair<_Size, _Size> __w = __weak_hash_len_32_with_seeds(__s + __len - 32, __y + __k1, __x);
-  __x = __x * __k1 + __loadword<_Size>(__s);
-
-  // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
-  __len = (__len - 1) & ~static_cast<_Size>(63);
-  do {
-    __x = __rotate(__x + __y + __v.first + __loadword<_Size>(__s + 8), 37) * __k1;
-    __y = __rotate(__y + __v.second + __loadword<_Size>(__s + 48), 42) * __k1;
-    __x ^= __w.second;
-    __y += __v.first + __loadword<_Size>(__s + 40);
-    __z = __rotate(__z + __w.first, 33) * __k1;
-    __v = __weak_hash_len_32_with_seeds(__s, __v.second * __k1, __x + __w.first);
-    __w = __weak_hash_len_32_with_seeds(__s + 32, __z + __w.second,
-                                        __y + __loadword<_Size>(__s + 16));
-    std::swap(__z, __x);
-    __s += 64;
-    __len -= 64;
-  } while (__len != 0);
-  return __hash_len_16(
-      __hash_len_16(__v.first, __w.first) + __shift_mix(__y) * __k1 + __z,
-      __hash_len_16(__v.second, __w.second) + __x);
-}
-
-template <class _Tp, size_t = sizeof(_Tp) / sizeof(size_t)>
-struct __scalar_hash;
-
-template <class _Tp>
-struct __scalar_hash<_Tp, 0>
-    : public unary_function<_Tp, size_t>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(_Tp __v) const _NOEXCEPT
-    {
-        union
-        {
-            _Tp    __t;
-            size_t __a;
-        } __u;
-        __u.__a = 0;
-        __u.__t = __v;
-        return __u.__a;
-    }
-};
-
-template <class _Tp>
-struct __scalar_hash<_Tp, 1>
-    : public unary_function<_Tp, size_t>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(_Tp __v) const _NOEXCEPT
-    {
-        union
-        {
-            _Tp    __t;
-            size_t __a;
-        } __u;
-        __u.__t = __v;
-        return __u.__a;
-    }
-};
-
-template <class _Tp>
-struct __scalar_hash<_Tp, 2>
-    : public unary_function<_Tp, size_t>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(_Tp __v) const _NOEXCEPT
-    {
-        union
-        {
-            _Tp __t;
-            struct
-            {
-                size_t __a;
-                size_t __b;
-            } __s;
-        } __u;
-        __u.__t = __v;
-        return __murmur2_or_cityhash<size_t>()(&__u, sizeof(__u));
-    }
-};
-
-template <class _Tp>
-struct __scalar_hash<_Tp, 3>
-    : public unary_function<_Tp, size_t>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(_Tp __v) const _NOEXCEPT
-    {
-        union
-        {
-            _Tp __t;
-            struct
-            {
-                size_t __a;
-                size_t __b;
-                size_t __c;
-            } __s;
-        } __u;
-        __u.__t = __v;
-        return __murmur2_or_cityhash<size_t>()(&__u, sizeof(__u));
-    }
-};
-
-template <class _Tp>
-struct __scalar_hash<_Tp, 4>
-    : public unary_function<_Tp, size_t>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(_Tp __v) const _NOEXCEPT
-    {
-        union
-        {
-            _Tp __t;
-            struct
-            {
-                size_t __a;
-                size_t __b;
-                size_t __c;
-                size_t __d;
-            } __s;
-        } __u;
-        __u.__t = __v;
-        return __murmur2_or_cityhash<size_t>()(&__u, sizeof(__u));
-    }
-};
-
-struct _PairT {
-  size_t first;
-  size_t second;
-};
-
-_LIBCPP_INLINE_VISIBILITY
-inline size_t __hash_combine(size_t __lhs, size_t __rhs) _NOEXCEPT {
-    typedef __scalar_hash<_PairT> _HashT;
-    const _PairT __p = {__lhs, __rhs};
-    return _HashT()(__p);
-}
-
-template<class _Tp>
-struct _LIBCPP_TEMPLATE_VIS hash<_Tp*>
-    : public unary_function<_Tp*, size_t>
-{
-    _LIBCPP_INLINE_VISIBILITY
-    size_t operator()(_Tp* __v) const _NOEXCEPT
-    {
-        union
-        {
-            _Tp* __t;
-            size_t __a;
-        } __u;
-        __u.__t = __v;
-        return __murmur2_or_cityhash<size_t>()(&__u, sizeof(__u));
-    }
-};
-
 template <class _Tp, class _Dp>
+#ifdef _LIBCPP_CXX03_LANG
 struct _LIBCPP_TEMPLATE_VIS hash<unique_ptr<_Tp, _Dp> >
+#else
+struct _LIBCPP_TEMPLATE_VIS hash<__enable_hash_helper<
+    unique_ptr<_Tp, _Dp>, typename unique_ptr<_Tp, _Dp>::pointer>>
+#endif
 {
     typedef unique_ptr<_Tp, _Dp> argument_type;
     typedef size_t               result_type;
@@ -5540,6 +5193,7 @@ struct _LIBCPP_TEMPLATE_VIS hash<shared_ptr<_Tp> >
 {
     typedef shared_ptr<_Tp>      argument_type;
     typedef size_t               result_type;
+
     _LIBCPP_INLINE_VISIBILITY
     result_type operator()(const argument_type& __ptr) const _NOEXCEPT
     {
index 86428f2..6e43501 100644 (file)
@@ -145,7 +145,7 @@ public:
 
 #endif  // defined(_LIBCPP_BUILDING_NEW) || (_LIBCPP_STD_VER > 11)
 
-#if !defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION) || _LIBCPP_STD_VER > 14
+#ifndef _LIBCPP_HAS_NO_ALIGNED_ALLOCATION
 #ifndef _LIBCPP_CXX03_LANG
 enum class _LIBCPP_ENUM_VIS align_val_t : size_t { };
 #else
index c002cc7..b13a2d5 100644 (file)
@@ -1295,7 +1295,9 @@ optional<_Tp> make_optional(initializer_list<_Up> __il,  _Args&&... __args)
 }
 
 template <class _Tp>
-struct _LIBCPP_TEMPLATE_VIS hash<optional<_Tp> >
+struct _LIBCPP_TEMPLATE_VIS hash<
+    __enable_hash_helper<optional<_Tp>, remove_const_t<_Tp>>
+>
 {
     typedef optional<_Tp> argument_type;
     typedef size_t        result_type;
@@ -1303,7 +1305,7 @@ struct _LIBCPP_TEMPLATE_VIS hash<optional<_Tp> >
     _LIBCPP_INLINE_VISIBILITY
     result_type operator()(const argument_type& __opt) const _NOEXCEPT
     {
-        return static_cast<bool>(__opt) ? hash<_Tp>()(*__opt) : 0;
+        return static_cast<bool>(__opt) ? hash<remove_const_t<_Tp>>()(*__opt) : 0;
     }
 };
 
index cc0646c..c230511 100644 (file)
@@ -198,6 +198,9 @@ template <size_t I>
 #include <__tuple>
 #include <type_traits>
 #include <initializer_list>
+#include <cstddef>
+#include <cstring>
+#include <cstdint>
 #include <__debug>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -930,6 +933,643 @@ using __is_inplace_type = __is_inplace_type_imp<__uncvref_t<_Tp>>;
 
 #endif // _LIBCPP_STD_VER > 14
 
+template <class _Arg, class _Result>
+struct _LIBCPP_TEMPLATE_VIS unary_function
+{
+    typedef _Arg    argument_type;
+    typedef _Result result_type;
+};
+
+template <class _Size>
+inline _LIBCPP_INLINE_VISIBILITY
+_Size
+__loadword(const void* __p)
+{
+    _Size __r;
+    std::memcpy(&__r, __p, sizeof(__r));
+    return __r;
+}
+
+// We use murmur2 when size_t is 32 bits, and cityhash64 when size_t
+// is 64 bits.  This is because cityhash64 uses 64bit x 64bit
+// multiplication, which can be very slow on 32-bit systems.
+template <class _Size, size_t = sizeof(_Size)*__CHAR_BIT__>
+struct __murmur2_or_cityhash;
+
+template <class _Size>
+struct __murmur2_or_cityhash<_Size, 32>
+{
+    _Size operator()(const void* __key, _Size __len);
+};
+
+// murmur2
+template <class _Size>
+_Size
+__murmur2_or_cityhash<_Size, 32>::operator()(const void* __key, _Size __len) _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK
+{
+    const _Size __m = 0x5bd1e995;
+    const _Size __r = 24;
+    _Size __h = __len;
+    const unsigned char* __data = static_cast<const unsigned char*>(__key);
+    for (; __len >= 4; __data += 4, __len -= 4)
+    {
+        _Size __k = __loadword<_Size>(__data);
+        __k *= __m;
+        __k ^= __k >> __r;
+        __k *= __m;
+        __h *= __m;
+        __h ^= __k;
+    }
+    switch (__len)
+    {
+    case 3:
+        __h ^= __data[2] << 16;
+    case 2:
+        __h ^= __data[1] << 8;
+    case 1:
+        __h ^= __data[0];
+        __h *= __m;
+    }
+    __h ^= __h >> 13;
+    __h *= __m;
+    __h ^= __h >> 15;
+    return __h;
+}
+
+template <class _Size>
+struct __murmur2_or_cityhash<_Size, 64>
+{
+    _Size operator()(const void* __key, _Size __len);
+
+ private:
+  // Some primes between 2^63 and 2^64.
+  static const _Size __k0 = 0xc3a5c85c97cb3127ULL;
+  static const _Size __k1 = 0xb492b66fbe98f273ULL;
+  static const _Size __k2 = 0x9ae16a3b2f90404fULL;
+  static const _Size __k3 = 0xc949d7c7509e6557ULL;
+
+  static _Size __rotate(_Size __val, int __shift) {
+    return __shift == 0 ? __val : ((__val >> __shift) | (__val << (64 - __shift)));
+  }
+
+  static _Size __rotate_by_at_least_1(_Size __val, int __shift) {
+    return (__val >> __shift) | (__val << (64 - __shift));
+  }
+
+  static _Size __shift_mix(_Size __val) {
+    return __val ^ (__val >> 47);
+  }
+
+  static _Size __hash_len_16(_Size __u, _Size __v) {
+    const _Size __mul = 0x9ddfea08eb382d69ULL;
+    _Size __a = (__u ^ __v) * __mul;
+    __a ^= (__a >> 47);
+    _Size __b = (__v ^ __a) * __mul;
+    __b ^= (__b >> 47);
+    __b *= __mul;
+    return __b;
+  }
+
+  static _Size __hash_len_0_to_16(const char* __s, _Size __len) {
+    if (__len > 8) {
+      const _Size __a = __loadword<_Size>(__s);
+      const _Size __b = __loadword<_Size>(__s + __len - 8);
+      return __hash_len_16(__a, __rotate_by_at_least_1(__b + __len, __len)) ^ __b;
+    }
+    if (__len >= 4) {
+      const uint32_t __a = __loadword<uint32_t>(__s);
+      const uint32_t __b = __loadword<uint32_t>(__s + __len - 4);
+      return __hash_len_16(__len + (__a << 3), __b);
+    }
+    if (__len > 0) {
+      const unsigned char __a = __s[0];
+      const unsigned char __b = __s[__len >> 1];
+      const unsigned char __c = __s[__len - 1];
+      const uint32_t __y = static_cast<uint32_t>(__a) +
+                           (static_cast<uint32_t>(__b) << 8);
+      const uint32_t __z = __len + (static_cast<uint32_t>(__c) << 2);
+      return __shift_mix(__y * __k2 ^ __z * __k3) * __k2;
+    }
+    return __k2;
+  }
+
+  static _Size __hash_len_17_to_32(const char *__s, _Size __len) {
+    const _Size __a = __loadword<_Size>(__s) * __k1;
+    const _Size __b = __loadword<_Size>(__s + 8);
+    const _Size __c = __loadword<_Size>(__s + __len - 8) * __k2;
+    const _Size __d = __loadword<_Size>(__s + __len - 16) * __k0;
+    return __hash_len_16(__rotate(__a - __b, 43) + __rotate(__c, 30) + __d,
+                         __a + __rotate(__b ^ __k3, 20) - __c + __len);
+  }
+
+  // Return a 16-byte hash for 48 bytes.  Quick and dirty.
+  // Callers do best to use "random-looking" values for a and b.
+  static pair<_Size, _Size> __weak_hash_len_32_with_seeds(
+      _Size __w, _Size __x, _Size __y, _Size __z, _Size __a, _Size __b) {
+    __a += __w;
+    __b = __rotate(__b + __a + __z, 21);
+    const _Size __c = __a;
+    __a += __x;
+    __a += __y;
+    __b += __rotate(__a, 44);
+    return pair<_Size, _Size>(__a + __z, __b + __c);
+  }
+
+  // Return a 16-byte hash for s[0] ... s[31], a, and b.  Quick and dirty.
+  static pair<_Size, _Size> __weak_hash_len_32_with_seeds(
+      const char* __s, _Size __a, _Size __b) {
+    return __weak_hash_len_32_with_seeds(__loadword<_Size>(__s),
+                                         __loadword<_Size>(__s + 8),
+                                         __loadword<_Size>(__s + 16),
+                                         __loadword<_Size>(__s + 24),
+                                         __a,
+                                         __b);
+  }
+
+  // Return an 8-byte hash for 33 to 64 bytes.
+  static _Size __hash_len_33_to_64(const char *__s, size_t __len) {
+    _Size __z = __loadword<_Size>(__s + 24);
+    _Size __a = __loadword<_Size>(__s) +
+                (__len + __loadword<_Size>(__s + __len - 16)) * __k0;
+    _Size __b = __rotate(__a + __z, 52);
+    _Size __c = __rotate(__a, 37);
+    __a += __loadword<_Size>(__s + 8);
+    __c += __rotate(__a, 7);
+    __a += __loadword<_Size>(__s + 16);
+    _Size __vf = __a + __z;
+    _Size __vs = __b + __rotate(__a, 31) + __c;
+    __a = __loadword<_Size>(__s + 16) + __loadword<_Size>(__s + __len - 32);
+    __z += __loadword<_Size>(__s + __len - 8);
+    __b = __rotate(__a + __z, 52);
+    __c = __rotate(__a, 37);
+    __a += __loadword<_Size>(__s + __len - 24);
+    __c += __rotate(__a, 7);
+    __a += __loadword<_Size>(__s + __len - 16);
+    _Size __wf = __a + __z;
+    _Size __ws = __b + __rotate(__a, 31) + __c;
+    _Size __r = __shift_mix((__vf + __ws) * __k2 + (__wf + __vs) * __k0);
+    return __shift_mix(__r * __k0 + __vs) * __k2;
+  }
+};
+
+// cityhash64
+template <class _Size>
+_Size
+__murmur2_or_cityhash<_Size, 64>::operator()(const void* __key, _Size __len) _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK
+{
+  const char* __s = static_cast<const char*>(__key);
+  if (__len <= 32) {
+    if (__len <= 16) {
+      return __hash_len_0_to_16(__s, __len);
+    } else {
+      return __hash_len_17_to_32(__s, __len);
+    }
+  } else if (__len <= 64) {
+    return __hash_len_33_to_64(__s, __len);
+  }
+
+  // For strings over 64 bytes we hash the end first, and then as we
+  // loop we keep 56 bytes of state: v, w, x, y, and z.
+  _Size __x = __loadword<_Size>(__s + __len - 40);
+  _Size __y = __loadword<_Size>(__s + __len - 16) +
+              __loadword<_Size>(__s + __len - 56);
+  _Size __z = __hash_len_16(__loadword<_Size>(__s + __len - 48) + __len,
+                          __loadword<_Size>(__s + __len - 24));
+  pair<_Size, _Size> __v = __weak_hash_len_32_with_seeds(__s + __len - 64, __len, __z);
+  pair<_Size, _Size> __w = __weak_hash_len_32_with_seeds(__s + __len - 32, __y + __k1, __x);
+  __x = __x * __k1 + __loadword<_Size>(__s);
+
+  // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
+  __len = (__len - 1) & ~static_cast<_Size>(63);
+  do {
+    __x = __rotate(__x + __y + __v.first + __loadword<_Size>(__s + 8), 37) * __k1;
+    __y = __rotate(__y + __v.second + __loadword<_Size>(__s + 48), 42) * __k1;
+    __x ^= __w.second;
+    __y += __v.first + __loadword<_Size>(__s + 40);
+    __z = __rotate(__z + __w.first, 33) * __k1;
+    __v = __weak_hash_len_32_with_seeds(__s, __v.second * __k1, __x + __w.first);
+    __w = __weak_hash_len_32_with_seeds(__s + 32, __z + __w.second,
+                                        __y + __loadword<_Size>(__s + 16));
+    std::swap(__z, __x);
+    __s += 64;
+    __len -= 64;
+  } while (__len != 0);
+  return __hash_len_16(
+      __hash_len_16(__v.first, __w.first) + __shift_mix(__y) * __k1 + __z,
+      __hash_len_16(__v.second, __w.second) + __x);
+}
+
+template <class _Tp, size_t = sizeof(_Tp) / sizeof(size_t)>
+struct __scalar_hash;
+
+template <class _Tp>
+struct __scalar_hash<_Tp, 0>
+    : public unary_function<_Tp, size_t>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(_Tp __v) const _NOEXCEPT
+    {
+        union
+        {
+            _Tp    __t;
+            size_t __a;
+        } __u;
+        __u.__a = 0;
+        __u.__t = __v;
+        return __u.__a;
+    }
+};
+
+template <class _Tp>
+struct __scalar_hash<_Tp, 1>
+    : public unary_function<_Tp, size_t>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(_Tp __v) const _NOEXCEPT
+    {
+        union
+        {
+            _Tp    __t;
+            size_t __a;
+        } __u;
+        __u.__t = __v;
+        return __u.__a;
+    }
+};
+
+template <class _Tp>
+struct __scalar_hash<_Tp, 2>
+    : public unary_function<_Tp, size_t>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(_Tp __v) const _NOEXCEPT
+    {
+        union
+        {
+            _Tp __t;
+            struct
+            {
+                size_t __a;
+                size_t __b;
+            } __s;
+        } __u;
+        __u.__t = __v;
+        return __murmur2_or_cityhash<size_t>()(&__u, sizeof(__u));
+    }
+};
+
+template <class _Tp>
+struct __scalar_hash<_Tp, 3>
+    : public unary_function<_Tp, size_t>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(_Tp __v) const _NOEXCEPT
+    {
+        union
+        {
+            _Tp __t;
+            struct
+            {
+                size_t __a;
+                size_t __b;
+                size_t __c;
+            } __s;
+        } __u;
+        __u.__t = __v;
+        return __murmur2_or_cityhash<size_t>()(&__u, sizeof(__u));
+    }
+};
+
+template <class _Tp>
+struct __scalar_hash<_Tp, 4>
+    : public unary_function<_Tp, size_t>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(_Tp __v) const _NOEXCEPT
+    {
+        union
+        {
+            _Tp __t;
+            struct
+            {
+                size_t __a;
+                size_t __b;
+                size_t __c;
+                size_t __d;
+            } __s;
+        } __u;
+        __u.__t = __v;
+        return __murmur2_or_cityhash<size_t>()(&__u, sizeof(__u));
+    }
+};
+
+struct _PairT {
+  size_t first;
+  size_t second;
+};
+
+_LIBCPP_INLINE_VISIBILITY
+inline size_t __hash_combine(size_t __lhs, size_t __rhs) _NOEXCEPT {
+    typedef __scalar_hash<_PairT> _HashT;
+    const _PairT __p = {__lhs, __rhs};
+    return _HashT()(__p);
+}
+
+template<class _Tp>
+struct _LIBCPP_TEMPLATE_VIS hash<_Tp*>
+    : public unary_function<_Tp*, size_t>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(_Tp* __v) const _NOEXCEPT
+    {
+        union
+        {
+            _Tp* __t;
+            size_t __a;
+        } __u;
+        __u.__t = __v;
+        return __murmur2_or_cityhash<size_t>()(&__u, sizeof(__u));
+    }
+};
+
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS hash<bool>
+    : public unary_function<bool, size_t>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(bool __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
+};
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS hash<char>
+    : public unary_function<char, size_t>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(char __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
+};
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS hash<signed char>
+    : public unary_function<signed char, size_t>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(signed char __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
+};
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS hash<unsigned char>
+    : public unary_function<unsigned char, size_t>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(unsigned char __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
+};
+
+#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS hash<char16_t>
+    : public unary_function<char16_t, size_t>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(char16_t __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
+};
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS hash<char32_t>
+    : public unary_function<char32_t, size_t>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(char32_t __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
+};
+
+#endif  // _LIBCPP_HAS_NO_UNICODE_CHARS
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS hash<wchar_t>
+    : public unary_function<wchar_t, size_t>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(wchar_t __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
+};
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS hash<short>
+    : public unary_function<short, size_t>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(short __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
+};
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS hash<unsigned short>
+    : public unary_function<unsigned short, size_t>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(unsigned short __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
+};
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS hash<int>
+    : public unary_function<int, size_t>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(int __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
+};
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS hash<unsigned int>
+    : public unary_function<unsigned int, size_t>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(unsigned int __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
+};
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS hash<long>
+    : public unary_function<long, size_t>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(long __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
+};
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS hash<unsigned long>
+    : public unary_function<unsigned long, size_t>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(unsigned long __v) const _NOEXCEPT {return static_cast<size_t>(__v);}
+};
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS hash<long long>
+    : public __scalar_hash<long long>
+{
+};
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS hash<unsigned long long>
+    : public __scalar_hash<unsigned long long>
+{
+};
+
+#ifndef _LIBCPP_HAS_NO_INT128
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS hash<__int128_t>
+    : public __scalar_hash<__int128_t>
+{
+};
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS hash<__uint128_t>
+    : public __scalar_hash<__uint128_t>
+{
+};
+
+#endif
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS hash<float>
+    : public __scalar_hash<float>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(float __v) const _NOEXCEPT
+    {
+        // -0.0 and 0.0 should return same hash
+       if (__v == 0)
+           return 0;
+        return __scalar_hash<float>::operator()(__v);
+    }
+};
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS hash<double>
+    : public __scalar_hash<double>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(double __v) const _NOEXCEPT
+    {
+        // -0.0 and 0.0 should return same hash
+       if (__v == 0)
+           return 0;
+        return __scalar_hash<double>::operator()(__v);
+    }
+};
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS hash<long double>
+    : public __scalar_hash<long double>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(long double __v) const _NOEXCEPT
+    {
+        // -0.0 and 0.0 should return same hash
+        if (__v == 0)
+            return 0;
+#if defined(__i386__)
+        // Zero out padding bits
+        union
+        {
+            long double __t;
+            struct
+            {
+                size_t __a;
+                size_t __b;
+                size_t __c;
+                size_t __d;
+            } __s;
+        } __u;
+        __u.__s.__a = 0;
+        __u.__s.__b = 0;
+        __u.__s.__c = 0;
+        __u.__s.__d = 0;
+        __u.__t = __v;
+        return __u.__s.__a ^ __u.__s.__b ^ __u.__s.__c ^ __u.__s.__d;
+#elif defined(__x86_64__)
+        // Zero out padding bits
+        union
+        {
+            long double __t;
+            struct
+            {
+                size_t __a;
+                size_t __b;
+            } __s;
+        } __u;
+        __u.__s.__a = 0;
+        __u.__s.__b = 0;
+        __u.__t = __v;
+        return __u.__s.__a ^ __u.__s.__b;
+#else
+        return __scalar_hash<long double>::operator()(__v);
+#endif
+    }
+};
+
+#if _LIBCPP_STD_VER > 11
+
+template <class _Tp, bool = is_enum<_Tp>::value>
+struct _LIBCPP_TEMPLATE_VIS __enum_hash
+    : public unary_function<_Tp, size_t>
+{
+    _LIBCPP_INLINE_VISIBILITY
+    size_t operator()(_Tp __v) const _NOEXCEPT
+    {
+        typedef typename underlying_type<_Tp>::type type;
+        return hash<type>{}(static_cast<type>(__v));
+    }
+};
+template <class _Tp>
+struct _LIBCPP_TEMPLATE_VIS __enum_hash<_Tp, false> {
+    __enum_hash() = delete;
+    __enum_hash(__enum_hash const&) = delete;
+    __enum_hash& operator=(__enum_hash const&) = delete;
+};
+
+template <class _Tp>
+struct _LIBCPP_TEMPLATE_VIS hash : public __enum_hash<_Tp>
+{
+};
+#endif
+
+#if _LIBCPP_STD_VER > 14
+
+template <>
+struct _LIBCPP_TEMPLATE_VIS hash<nullptr_t>
+  : public unary_function<nullptr_t, size_t>
+{
+  _LIBCPP_INLINE_VISIBILITY
+  size_t operator()(nullptr_t) const _NOEXCEPT {
+    return 662607004ull;
+  }
+};
+#endif
+
+#ifndef _LIBCPP_CXX03_LANG
+template <class _Key, class _Hash = std::hash<_Key> >
+using __has_enabled_hash = integral_constant<bool,
+    is_default_constructible<_Hash>::value &&
+    is_copy_constructible<_Hash>::value &&
+    is_move_constructible<_Hash>::value &&
+    __invokable_r<size_t, _Hash, _Key const&>::value
+>;
+
+#if _LIBCPP_STD_VER > 14
+template <class _Type, class>
+using __enable_hash_helper_imp = _Type;
+
+template <class _Type, class ..._Keys>
+using __enable_hash_helper = __enable_hash_helper_imp<_Type,
+  typename enable_if<__all<__has_enabled_hash<_Keys>::value...>::value>::type
+>;
+#else
+template <class _Type, class ...>
+using __enable_hash_helper = _Type;
+#endif
+
+#endif // !_LIBCPP_CXX03_LANG
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif  // _LIBCPP_UTILITY
index 4396f10..67d4e3c 100644 (file)
@@ -1534,7 +1534,8 @@ auto swap(variant<_Types...>& __lhs,
 }
 
 template <class... _Types>
-struct _LIBCPP_TEMPLATE_VIS hash<variant<_Types...>> {
+struct _LIBCPP_TEMPLATE_VIS hash<
+    __enable_hash_helper<variant<_Types...>, remove_const_t<_Types>...>> {
   using argument_type = variant<_Types...>;
   using result_type = size_t;
 
@@ -1547,7 +1548,8 @@ struct _LIBCPP_TEMPLATE_VIS hash<variant<_Types...>> {
                : __variant::__visit_alt(
                      [](const auto& __alt) {
                        using __alt_type = decay_t<decltype(__alt)>;
-                       using __value_type = typename __alt_type::__value_type;
+                       using __value_type = remove_const_t<
+                         typename __alt_type::__value_type>;
                        return hash<__value_type>{}(__alt.__value);
                      },
                      __v);
index ae48c73..0d90258 100644 (file)
@@ -423,15 +423,6 @@ class Configuration(object):
         if not std:
             # Choose the newest possible language dialect if none is given.
             possible_stds = ['c++1z', 'c++14', 'c++11', 'c++03']
-            if self.cxx.type == 'gcc':
-                maj_v, _, _ = self.cxx.version
-                maj_v = int(maj_v)
-                if maj_v < 7:
-                    possible_stds.remove('c++1z')
-                # FIXME: How many C++14 tests actually fail under GCC 5 and 6?
-                # Should we XFAIL them individually instead?
-                if maj_v <= 6:
-                    possible_stds.remove('c++14')
             for s in possible_stds:
                 if self.cxx.hasCompileFlag('-std=%s' % s):
                     std = s
diff --git a/libcxx/test/std/containers/sequences/vector.bool/enabled_hash.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/enabled_hash.pass.cpp
new file mode 100644 (file)
index 0000000..f8a8dbd
--- /dev/null
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <vector>
+
+// Test that <vector> provides all of the arithmetic, enum, and pointer
+// hash specializations.
+
+#include <vector>
+
+#include "poisoned_hash_helper.hpp"
+#include "min_allocator.h"
+
+int main() {
+  test_library_hash_specializations_available();
+  {
+    test_hash_enabled_for_type<std::vector<bool> >();
+    test_hash_enabled_for_type<std::vector<bool, min_allocator<bool>>>();
+  }
+}
diff --git a/libcxx/test/std/diagnostics/syserr/syserr.hash/enabled_hash.pass.cpp b/libcxx/test/std/diagnostics/syserr/syserr.hash/enabled_hash.pass.cpp
new file mode 100644 (file)
index 0000000..f1b4605
--- /dev/null
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <system_error>
+
+// Test that <system_error> provides all of the arithmetic, enum, and pointer
+// hash specializations.
+
+#include <system_error>
+
+#include "poisoned_hash_helper.hpp"
+
+int main() {
+  test_library_hash_specializations_available();
+  {
+    test_hash_enabled_for_type<std::error_code>();
+    test_hash_enabled_for_type<std::error_condition>();
+  }
+}
diff --git a/libcxx/test/std/strings/basic.string.hash/enabled_hashes.pass.cpp b/libcxx/test/std/strings/basic.string.hash/enabled_hashes.pass.cpp
new file mode 100644 (file)
index 0000000..01f0121
--- /dev/null
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <string>
+
+// Test that <string> provides all of the arithmetic, enum, and pointer
+// hash specializations.
+
+#include <string>
+
+#include "poisoned_hash_helper.hpp"
+
+int main() {
+  test_library_hash_specializations_available();
+  {
+    test_hash_enabled_for_type<std::string>();
+    test_hash_enabled_for_type<std::wstring>();
+#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
+    test_hash_enabled_for_type<std::u16string>();
+    test_hash_enabled_for_type<std::u32string>();
+#endif
+  }
+}
diff --git a/libcxx/test/std/strings/string.view/string.view.hash/enabled_hashes.pass.cpp b/libcxx/test/std/strings/string.view/string.view.hash/enabled_hashes.pass.cpp
new file mode 100644 (file)
index 0000000..2e9ebcb
--- /dev/null
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <string_view>
+
+// Test that <string_view> provides all of the arithmetic, enum, and pointer
+// hash specializations.
+
+#include <string_view>
+
+#include "poisoned_hash_helper.hpp"
+
+int main() {
+  test_library_hash_specializations_available();
+  {
+    test_hash_enabled_for_type<std::string_view>();
+    test_hash_enabled_for_type<std::wstring_view>();
+#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
+    test_hash_enabled_for_type<std::u16string_view>();
+    test_hash_enabled_for_type<std::u32string_view>();
+#endif
+  }
+}
index 63099e2..d076648 100644 (file)
 // Not very portable
 
 #include <string_view>
+#include <string>
 #include <cassert>
 #include <type_traits>
 
 using std::string_view;
 
-template <class T>
+template <class SV>
 void
 test()
 {
-    typedef std::hash<T> H;
-    static_assert((std::is_same<typename H::argument_type, T>::value), "" );
+    typedef std::hash<SV> H;
+    static_assert((std::is_same<typename H::argument_type, SV>::value), "" );
     static_assert((std::is_same<typename H::result_type, std::size_t>::value), "" );
-    H h;
-//     std::string g1 = "1234567890";
-//     std::string g2 = "1234567891";
-    typedef typename T::value_type char_type;
+
+    typedef typename SV::value_type char_type;
+    typedef std::basic_string<char_type> String;
+    typedef std::hash<String> SH;
+
     char_type g1 [ 10 ];
     char_type g2 [ 10 ];
     for ( int i = 0; i < 10; ++i )
         g1[i] = g2[9-i] = static_cast<char_type>('0' + i);
-    T s1(g1, 10);
-    T s2(g2, 10);
+    H h;
+    SH sh;
+    SV s1(g1, 10);
+    String ss1(s1);
+    SV s2(g2, 10);
+    String ss2(s2);
+    assert(h(s1) == h(s1));
     assert(h(s1) != h(s2));
+    assert(sh(ss1) == h(s1));
+    assert(sh(ss2) == h(s2));
 }
 
 int main()
diff --git a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/enabled_hashes.pass.cpp b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/enabled_hashes.pass.cpp
new file mode 100644 (file)
index 0000000..9799467
--- /dev/null
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: libcpp-has-no-threads
+// UNSUPPORTED: c++98, c++03
+
+// <thread>
+
+// Test that <thread> provides all of the arithmetic, enum, and pointer
+// hash specializations.
+
+#include <thread>
+
+#include "poisoned_hash_helper.hpp"
+
+int main() {
+  test_library_hash_specializations_available();
+  {
+    test_hash_enabled_for_type<std::thread::id>();
+  }
+}
diff --git a/libcxx/test/std/utilities/function.objects/unord.hash/enabled_hashes.pass.cpp b/libcxx/test/std/utilities/function.objects/unord.hash/enabled_hashes.pass.cpp
new file mode 100644 (file)
index 0000000..775247f
--- /dev/null
@@ -0,0 +1,23 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <functional>
+
+// Test that <functional> provides all of the arithmetic, enum, and pointer
+// hash specializations.
+
+#include <functional>
+
+#include "poisoned_hash_helper.hpp"
+
+int main() {
+  test_library_hash_specializations_available();
+}
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.hash/enabled_hash.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.hash/enabled_hash.pass.cpp
new file mode 100644 (file)
index 0000000..e9237c5
--- /dev/null
@@ -0,0 +1,23 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <memory>
+
+// Test that <memory> provides all of the arithmetic, enum, and pointer
+// hash specializations.
+
+#include <memory>
+
+#include "poisoned_hash_helper.hpp"
+
+int main() {
+  test_library_hash_specializations_available();
+}
index 990cb58..5fba1fc 100644 (file)
 #include <memory>
 #include <cassert>
 
+#if TEST_STD_VER >= 11
+#include "poisoned_hash_helper.hpp"
+
+struct A {};
+#endif
+
 int main()
 {
+  {
     int* ptr = new int;
     std::shared_ptr<int> p(ptr);
     std::hash<std::shared_ptr<int> > f;
     std::size_t h = f(p);
     assert(h == std::hash<int*>()(ptr));
+  }
+#if TEST_STD_VER >= 11
+  {
+    test_hash_enabled_for_type<std::shared_ptr<int>>();
+    test_hash_enabled_for_type<std::shared_ptr<A>>();
+  }
+#endif
 }
index 5cd4ab1..f989a01 100644 (file)
 #include <memory>
 #include <cassert>
 
+#include "test_macros.h"
+
+#if TEST_STD_VER >= 11
+#include "poisoned_hash_helper.hpp"
+#include "deleter_types.h"
+#include "min_allocator.h"
+
+template <class ValueT, class Del>
+void test_enabled_with_deleter() {
+  using UPtr = std::unique_ptr<ValueT, Del>;
+  using pointer = typename UPtr::pointer;
+  using RawDel = typename std::decay<Del>::type;
+  RawDel d(1);
+  UPtr p(nullptr, std::forward<Del>(d));
+  test_hash_enabled_for_type<UPtr>(p);
+  test_hash_enabled_for_type<pointer>();
+}
+
+template <class ValueT, class Del>
+void test_disabled_with_deleter() {
+  using UPtr = std::unique_ptr<ValueT, Del>;
+  using pointer = typename UPtr::pointer;
+  test_hash_disabled_for_type<UPtr>();
+  test_hash_disabled_for_type<pointer>();
+}
+
+template <class T>
+struct std::hash<min_pointer<T, std::integral_constant<size_t, 1>>> {
+  size_t operator()(min_pointer<T, std::integral_constant<size_t, 1>> p) const {
+    if (!p) return 0;
+    return std::hash<T*>{}(std::addressof(*p));
+  }
+};
+
+struct A {};
+
+#endif // TEST_STD_VER >= 11
+
 int main()
 {
+  {
     int* ptr = new int;
     std::unique_ptr<int> p(ptr);
     std::hash<std::unique_ptr<int> > f;
     std::size_t h = f(p);
     assert(h == std::hash<int*>()(ptr));
+  }
+#if TEST_STD_VER >= 11
+  {
+    test_enabled_with_deleter<int, Deleter<int>>();
+    test_enabled_with_deleter<int[], Deleter<int[]>>();
+    test_enabled_with_deleter<int, CopyDeleter<int>>();
+    test_enabled_with_deleter<int, CopyDeleter<int[]>>();
+    test_enabled_with_deleter<int, NCDeleter<int>&>();
+    test_enabled_with_deleter<int[], NCDeleter<int[]>&>();
+    test_enabled_with_deleter<int, NCConstDeleter<int> const&>();
+    test_enabled_with_deleter<int[], NCConstDeleter<int[]> const&>();
+  }
+  {
+    test_enabled_with_deleter<int, PointerDeleter<int, 1>>();
+    test_enabled_with_deleter<int[], PointerDeleter<int[], 1>>();
+    test_enabled_with_deleter<A, PointerDeleter<A, 1>>();
+    test_enabled_with_deleter<A[], PointerDeleter<A[], 1>>();
+
+#if TEST_STD_VER > 14
+    test_disabled_with_deleter<int, PointerDeleter<int, 0>>();
+    test_disabled_with_deleter<int[], PointerDeleter<int[], 0>>();
+    test_disabled_with_deleter<A, PointerDeleter<A, 0>>();
+    test_disabled_with_deleter<A[], PointerDeleter<A[], 0>>();
+#endif
+  }
+#endif
 }
diff --git a/libcxx/test/std/utilities/optional/optional.hash/enabled_hash.pass.cpp b/libcxx/test/std/utilities/optional/optional.hash/enabled_hash.pass.cpp
new file mode 100644 (file)
index 0000000..e54a4ce
--- /dev/null
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+
+// <optional>
+
+// Test that <optional> provides all of the arithmetic, enum, and pointer
+// hash specializations.
+
+#include <optional>
+
+#include "poisoned_hash_helper.hpp"
+
+int main() {
+  test_library_hash_specializations_available();
+  {
+
+  }
+}
index dfdd07d..ea89dc3 100644 (file)
 #include <memory>
 #include <cassert>
 
+#include "poisoned_hash_helper.hpp"
+
+struct A {};
+struct B {};
+
+template <>
+struct std::hash<B> {
+  size_t operator()(B const&) { return 0; }
+};
 
 int main()
 {
@@ -45,4 +54,16 @@ int main()
         opt = std::unique_ptr<int>(new int(3));
         assert(std::hash<optional<T>>{}(opt) == std::hash<T>{}(*opt));
     }
+    {
+      test_hash_enabled_for_type<std::optional<int> >();
+      test_hash_enabled_for_type<std::optional<int*> >();
+      test_hash_enabled_for_type<std::optional<const int> >();
+      test_hash_enabled_for_type<std::optional<int* const> >();
+
+      test_hash_disabled_for_type<std::optional<A>>();
+      test_hash_disabled_for_type<std::optional<const A>>();
+
+      test_hash_enabled_for_type<std::optional<B>>();
+      test_hash_enabled_for_type<std::optional<const B>>();
+    }
 }
diff --git a/libcxx/test/std/utilities/template.bitset/bitset.hash/enabled_hash.pass.cpp b/libcxx/test/std/utilities/template.bitset/bitset.hash/enabled_hash.pass.cpp
new file mode 100644 (file)
index 0000000..1d8bff4
--- /dev/null
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <bitset>
+
+// Test that <bitset> provides all of the arithmetic, enum, and pointer
+// hash specializations.
+
+#include <bitset>
+
+#include "poisoned_hash_helper.hpp"
+
+int main() {
+  test_library_hash_specializations_available();
+  {
+    test_hash_enabled_for_type<std::bitset<0> >();
+    test_hash_enabled_for_type<std::bitset<1> >();
+    test_hash_enabled_for_type<std::bitset<1024> >();
+    test_hash_enabled_for_type<std::bitset<100000> >();
+  }
+}
diff --git a/libcxx/test/std/utilities/type.index/type.index.hash/enabled_hash.pass.cpp b/libcxx/test/std/utilities/type.index/type.index.hash/enabled_hash.pass.cpp
new file mode 100644 (file)
index 0000000..26bada3
--- /dev/null
@@ -0,0 +1,23 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <typeindex>
+
+// Test that <typeindex> provides all of the arithmetic, enum, and pointer
+// hash specializations.
+
+#include <typeindex>
+
+#include "poisoned_hash_helper.hpp"
+
+int main() {
+  test_library_hash_specializations_available();
+}
index 6d353f1..0fe020b 100644 (file)
 #include <typeindex>
 #include <type_traits>
 
+#include "test_macros.h"
+#if TEST_STD_VER >= 11
+#include "poisoned_hash_helper.hpp"
+#endif
+
 int main()
 {
+  {
     typedef std::hash<std::type_index> H;
     static_assert((std::is_same<typename H::argument_type, std::type_index>::value), "" );
     static_assert((std::is_same<typename H::result_type, std::size_t>::value), "" );
+  }
+  {
+    test_hash_enabled_for_type<std::type_index>(std::type_index(typeid(int)));
+  }
 }
diff --git a/libcxx/test/std/utilities/variant/variant.hash/enabled_hash.pass.cpp b/libcxx/test/std/utilities/variant/variant.hash/enabled_hash.pass.cpp
new file mode 100644 (file)
index 0000000..826dcba
--- /dev/null
@@ -0,0 +1,23 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+
+// <variant>
+
+// Test that <variant> provides all of the arithmetic, enum, and pointer
+// hash specializations.
+
+#include <variant>
+
+#include "poisoned_hash_helper.hpp"
+
+int main() {
+  test_library_hash_specializations_available();
+}
index d807a7c..96ef967 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "test_macros.h"
 #include "variant_test_helpers.hpp"
+#include "poisoned_hash_helper.hpp"
 
 #ifndef TEST_HAS_NO_EXCEPTIONS
 namespace std {
@@ -103,6 +104,9 @@ void test_hash_monostate() {
     ASSERT_SAME_TYPE(decltype(h(m1)), std::size_t);
     static_assert(std::is_copy_constructible<H>::value, "");
   }
+  {
+    test_hash_enabled_for_type<std::monostate>();
+  }
 }
 
 void test_hash_variant_duplicate_elements() {
@@ -117,8 +121,34 @@ void test_hash_variant_duplicate_elements() {
     LIBCPP_ASSERT(h(v1) != h(v2));
 }
 
+struct A {};
+struct B {};
+
+template <>
+struct std::hash<B> {
+  size_t operator()(B const&) const {
+    return 0;
+  }
+};
+
+void test_hash_variant_enabled() {
+  {
+    test_hash_enabled_for_type<std::variant<int> >();
+    test_hash_enabled_for_type<std::variant<int*, long, double, const int> >();
+  }
+  {
+    test_hash_disabled_for_type<std::variant<int, A>>();
+    test_hash_disabled_for_type<std::variant<const A, void*>>();
+  }
+  {
+    test_hash_enabled_for_type<std::variant<int, B>>();
+    test_hash_enabled_for_type<std::variant<const B, int>>();
+  }
+}
+
 int main() {
   test_hash_variant();
   test_hash_variant_duplicate_elements();
   test_hash_monostate();
+  test_hash_variant_enabled();
 }
index c8b3820..f7cdb62 100644 (file)
@@ -21,6 +21,7 @@
 #include <cassert>
 
 #include "test_macros.h"
+#include "min_allocator.h"
 
 #if TEST_STD_VER >= 11
 
@@ -379,4 +380,63 @@ swap(test_deleter<T>& x, test_deleter<T>& y)
     y = std::move(t);
 }
 
+#if TEST_STD_VER >= 11
+
+template <class T, size_t ID = 0>
+class PointerDeleter
+{
+    PointerDeleter(const PointerDeleter&);
+    PointerDeleter& operator=(const PointerDeleter&);
+
+public:
+    typedef min_pointer<T, std::integral_constant<size_t, ID>> pointer;
+
+    PointerDeleter() = default;
+    PointerDeleter(PointerDeleter&&) = default;
+    PointerDeleter& operator=(PointerDeleter&&) = default;
+    explicit PointerDeleter(int) {}
+
+    template <class U>
+        PointerDeleter(PointerDeleter<U, ID>&&,
+            typename std::enable_if<!std::is_same<U, T>::value>::type* = 0)
+    {}
+
+    void operator()(pointer p) { if (p) { delete std::addressof(*p); }}
+
+private:
+    template <class U>
+        PointerDeleter(const PointerDeleter<U, ID>&,
+            typename std::enable_if<!std::is_same<U, T>::value>::type* = 0);
+};
+
+
+template <class T, size_t ID>
+class PointerDeleter<T[], ID>
+{
+    PointerDeleter(const PointerDeleter&);
+    PointerDeleter& operator=(const PointerDeleter&);
+
+public:
+    typedef min_pointer<T, std::integral_constant<size_t, ID> > pointer;
+
+    PointerDeleter() = default;
+    PointerDeleter(PointerDeleter&&) = default;
+    PointerDeleter& operator=(PointerDeleter&&) = default;
+    explicit PointerDeleter(int) {}
+
+    template <class U>
+        PointerDeleter(PointerDeleter<U, ID>&&,
+            typename std::enable_if<!std::is_same<U, T>::value>::type* = 0)
+    {}
+
+    void operator()(pointer p) { if (p) { delete [] std::addressof(*p); }}
+
+private:
+    template <class U>
+        PointerDeleter(const PointerDeleter<U, ID>&,
+            typename std::enable_if<!std::is_same<U, T>::value>::type* = 0);
+};
+
+#endif // TEST_STD_VER >= 11
+
 #endif  // SUPPORT_DELETER_TYPES_H
index d518e4a..a3af9e1 100644 (file)
@@ -136,31 +136,31 @@ public:
 
 #include <memory>
 
-template <class T> class min_pointer;
-template <class T> class min_pointer<const T>;
-template <> class min_pointer<void>;
-template <> class min_pointer<const void>;
+template <class T, class = std::integral_constant<size_t, 0> > class min_pointer;
+template <class T, class ID> class min_pointer<const T, ID>;
+template <class ID> class min_pointer<void, ID>;
+template <class ID> class min_pointer<const void, ID>;
 template <class T> class min_allocator;
 
-template <>
-class min_pointer<const void>
+template <class ID>
+class min_pointer<const void, ID>
 {
     const void* ptr_;
 public:
     min_pointer() TEST_NOEXCEPT = default;
     min_pointer(std::nullptr_t) TEST_NOEXCEPT : ptr_(nullptr) {}
     template <class T>
-    min_pointer(min_pointer<T> p) TEST_NOEXCEPT : ptr_(p.ptr_) {}
+    min_pointer(min_pointer<T, ID> p) TEST_NOEXCEPT : ptr_(p.ptr_) {}
 
     explicit operator bool() const {return ptr_ != nullptr;}
 
     friend bool operator==(min_pointer x, min_pointer y) {return x.ptr_ == y.ptr_;}
     friend bool operator!=(min_pointer x, min_pointer y) {return !(x == y);}
-    template <class U> friend class min_pointer;
+    template <class U, class XID> friend class min_pointer;
 };
 
-template <>
-class min_pointer<void>
+template <class ID>
+class min_pointer<void, ID>
 {
     void* ptr_;
 public:
@@ -172,16 +172,16 @@ public:
                             !std::is_const<T>::value
                        >::type
              >
-    min_pointer(min_pointer<T> p) TEST_NOEXCEPT : ptr_(p.ptr_) {}
+    min_pointer(min_pointer<T, ID> p) TEST_NOEXCEPT : ptr_(p.ptr_) {}
 
     explicit operator bool() const {return ptr_ != nullptr;}
 
     friend bool operator==(min_pointer x, min_pointer y) {return x.ptr_ == y.ptr_;}
     friend bool operator!=(min_pointer x, min_pointer y) {return !(x == y);}
-    template <class U> friend class min_pointer;
+    template <class U, class XID> friend class min_pointer;
 };
 
-template <class T>
+template <class T, class ID>
 class min_pointer
 {
     T* ptr_;
@@ -190,7 +190,7 @@ class min_pointer
 public:
     min_pointer() TEST_NOEXCEPT = default;
     min_pointer(std::nullptr_t) TEST_NOEXCEPT : ptr_(nullptr) {}
-    explicit min_pointer(min_pointer<void> p) TEST_NOEXCEPT : ptr_(static_cast<T*>(p.ptr_)) {}
+    explicit min_pointer(min_pointer<void, ID> p) TEST_NOEXCEPT : ptr_(static_cast<T*>(p.ptr_)) {}
 
     explicit operator bool() const {return ptr_ != nullptr;}
 
@@ -247,12 +247,12 @@ public:
 
     friend bool operator==(min_pointer x, min_pointer y) {return x.ptr_ == y.ptr_;}
     friend bool operator!=(min_pointer x, min_pointer y) {return !(x == y);}
-    template <class U> friend class min_pointer;
+    template <class U, class XID> friend class min_pointer;
     template <class U> friend class min_allocator;
 };
 
-template <class T>
-class min_pointer<const T>
+template <class T, class ID>
+class min_pointer<const T, ID>
 {
     const T* ptr_;
 
@@ -260,8 +260,8 @@ class min_pointer<const T>
 public:
     min_pointer() TEST_NOEXCEPT = default;
     min_pointer(std::nullptr_t) : ptr_(nullptr) {}
-    min_pointer(min_pointer<T> p) : ptr_(p.ptr_) {}
-    explicit min_pointer(min_pointer<const void> p) : ptr_(static_cast<const T*>(p.ptr_)) {}
+    min_pointer(min_pointer<T, ID> p) : ptr_(p.ptr_) {}
+    explicit min_pointer(min_pointer<const void, ID> p) : ptr_(static_cast<const T*>(p.ptr_)) {}
 
     explicit operator bool() const {return ptr_ != nullptr;}
 
@@ -318,37 +318,37 @@ public:
 
     friend bool operator==(min_pointer x, min_pointer y) {return x.ptr_ == y.ptr_;}
     friend bool operator!=(min_pointer x, min_pointer y) {return !(x == y);}
-    template <class U> friend class min_pointer;
+    template <class U, class XID> friend class min_pointer;
 };
 
-template <class T>
+template <class T, class ID>
 inline
 bool
-operator==(min_pointer<T> x, std::nullptr_t)
+operator==(min_pointer<T, ID> x, std::nullptr_t)
 {
     return !static_cast<bool>(x);
 }
 
-template <class T>
+template <class T, class ID>
 inline
 bool
-operator==(std::nullptr_t, min_pointer<T> x)
+operator==(std::nullptr_t, min_pointer<T, ID> x)
 {
     return !static_cast<bool>(x);
 }
 
-template <class T>
+template <class T, class ID>
 inline
 bool
-operator!=(min_pointer<T> x, std::nullptr_t)
+operator!=(min_pointer<T, ID> x, std::nullptr_t)
 {
     return static_cast<bool>(x);
 }
 
-template <class T>
+template <class T, class ID>
 inline
 bool
-operator!=(std::nullptr_t, min_pointer<T> x)
+operator!=(std::nullptr_t, min_pointer<T, ID> x)
 {
     return static_cast<bool>(x);
 }
diff --git a/libcxx/test/support/poisoned_hash_helper.hpp b/libcxx/test/support/poisoned_hash_helper.hpp
new file mode 100644 (file)
index 0000000..0a5675a
--- /dev/null
@@ -0,0 +1,244 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SUPPORT_POISONED_HASH_HELPER_HPP
+#define SUPPORT_POISONED_HASH_HELPER_HPP
+
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+
+#if TEST_STD_VER < 11
+#error this header may only be used in C++11 or newer
+#endif
+
+template <class ...Args> struct TypeList;
+
+// Test that the specified Hash meets the requirements of an enabled hash
+template <class Hash, class Key, class InputKey = Key>
+void test_hash_enabled(InputKey const& key = InputKey{});
+
+template <class T, class InputKey = T>
+void test_hash_enabled_for_type(InputKey const& key = InputKey{}) {
+  return test_hash_enabled<std::hash<T>, T, InputKey>(key);
+}
+
+// Test that the specified Hash meets the requirements of a disabled hash.
+template <class Hash, class Key>
+void test_hash_disabled();
+
+template <class T>
+void test_hash_disabled_for_type() {
+  return test_hash_disabled<std::hash<T>, T>();
+}
+
+namespace PoisonedHashDetail {
+  enum Enum {};
+  enum EnumClass : bool {};
+  struct Class {};
+}
+
+// Each header that declares the template hash provides enabled
+// specializations of hash for nullptr t and all cv-unqualified
+// arithmetic, enumeration, and pointer types.
+using LibraryHashTypes = TypeList<
+#if TEST_STD_VER > 14
+      decltype(nullptr),
+#endif
+      bool,
+      char,
+      signed char,
+      unsigned char,
+      wchar_t,
+#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
+      char16_t,
+      char32_t,
+#endif
+      short,
+      unsigned short,
+      int,
+      unsigned int,
+      long,
+      unsigned long,
+      long long,
+      unsigned long long,
+#ifndef _LIBCPP_HAS_NO_INT128
+      __int128_t,
+      __uint128_t,
+#endif
+      float,
+      double,
+      long double,
+#if TEST_STD_VER >= 14
+      // Enum types
+      PoisonedHashDetail::Enum,
+      PoisonedHashDetail::EnumClass,
+#endif
+      // pointer types
+      void*,
+      void const*,
+      PoisonedHashDetail::Class*
+    >;
+
+
+// Test that each of the library hash specializations for  arithmetic types,
+// enum types, and pointer types are available and enabled.
+template <class Types = LibraryHashTypes>
+void test_library_hash_specializations_available(Types = Types{});
+
+
+namespace PoisonedHashDetail {
+
+template <class T, class = typename T::foo_bar_baz>
+constexpr bool instantiate(int) { return true; }
+template <class> constexpr bool instantiate(long) { return true; }
+template <class T> constexpr bool instantiate() { return instantiate<T>(0); }
+
+template <class To>
+struct ConvertibleToSimple {
+  operator To() const {
+    return To{};
+  }
+};
+
+template <class To>
+struct ConvertibleTo {
+  To to{};
+  operator To&() & { return to; }
+  operator To const&() const & { return to; }
+  operator To&&() && { return std::move(to); }
+  operator To const&&() const && { return std::move(to); }
+};
+
+template <class HashExpr,
+         class Res = typename std::result_of<HashExpr>::type>
+constexpr bool can_hash(int) {
+  return std::is_same<Res, size_t>::value;
+}
+template <class> constexpr bool can_hash(long) { return false; }
+template <class T> constexpr bool can_hash() { return can_hash<T>(0); }
+
+} // namespace PoisonedHashDetail
+
+template <class Hash, class Key, class InputKey>
+void test_hash_enabled(InputKey const& key) {
+  using namespace PoisonedHashDetail;
+
+  static_assert(std::is_destructible<Hash>::value, "");
+  // Enabled hash requirements
+  static_assert(std::is_default_constructible<Hash>::value, "");
+  static_assert(std::is_copy_constructible<Hash>::value, "");
+  static_assert(std::is_move_constructible<Hash>::value, "");
+  static_assert(std::is_copy_assignable<Hash>::value, "");
+  static_assert(std::is_move_assignable<Hash>::value, "");
+
+#if TEST_STD_VER > 14
+  static_assert(std::is_swappable<Hash>::value, "");
+#elif defined(_LIBCPP_VERSION)
+  static_assert(std::__is_swappable<Hash>::value, "");
+#endif
+
+  // Hashable requirements
+  using CKey = ConvertibleTo<Key>;
+  static_assert(can_hash<Hash(Key&)>(), "");
+  static_assert(can_hash<Hash(Key const&)>(), "");
+  static_assert(can_hash<Hash(Key&&)>(), "");
+  static_assert(can_hash<Hash const&(Key&)>(), "");
+  static_assert(can_hash<Hash const&(Key const&)>(), "");
+  static_assert(can_hash<Hash const&(Key&&)>(), "");
+
+  static_assert(can_hash<Hash(ConvertibleToSimple<Key>&)>(), "");
+  static_assert(can_hash<Hash(ConvertibleToSimple<Key> const&)>(), "");
+  static_assert(can_hash<Hash(ConvertibleToSimple<Key>&&)>(), "");
+
+  static_assert(can_hash<Hash(ConvertibleTo<Key>&)>(), "");
+  static_assert(can_hash<Hash(ConvertibleTo<Key> const&)>(), "");
+  static_assert(can_hash<Hash(ConvertibleTo<Key> &&)>(), "");
+  static_assert(can_hash<Hash(ConvertibleTo<Key> const&&)>(), "");
+
+  const Hash h;
+  assert(h(key) == h(key));
+
+}
+
+template <class Hash, class Key>
+void test_hash_disabled() {
+  using namespace PoisonedHashDetail;
+
+  // Disabled hash requirements
+  static_assert(!std::is_default_constructible<Hash>::value, "");
+  static_assert(!std::is_copy_constructible<Hash>::value, "");
+  static_assert(!std::is_move_constructible<Hash>::value, "");
+  static_assert(!std::is_copy_assignable<Hash>::value, "");
+  static_assert(!std::is_move_assignable<Hash>::value, "");
+
+  static_assert(!std::is_function<
+      typename std::remove_pointer<
+          typename std::remove_reference<Hash>::type
+      >::type
+    >::value, "");
+
+  // Hashable requirements
+  using CKey = ConvertibleTo<Key>;
+  static_assert(!can_hash<Hash(Key&)>(), "");
+  static_assert(!can_hash<Hash(Key const&)>(), "");
+  static_assert(!can_hash<Hash(Key&&)>(), "");
+  static_assert(!can_hash<Hash const&(Key&)>(), "");
+  static_assert(!can_hash<Hash const&(Key const&)>(), "");
+  static_assert(!can_hash<Hash const&(Key&&)>(), "");
+
+  static_assert(!can_hash<Hash(ConvertibleToSimple<Key>&)>(), "");
+  static_assert(!can_hash<Hash(ConvertibleToSimple<Key> const&)>(), "");
+  static_assert(!can_hash<Hash(ConvertibleToSimple<Key>&&)>(), "");
+
+  static_assert(!can_hash<Hash(ConvertibleTo<Key>&)>(), "");
+  static_assert(!can_hash<Hash(ConvertibleTo<Key> const&)>(), "");
+  static_assert(!can_hash<Hash(ConvertibleTo<Key> &&)>(), "");
+  static_assert(!can_hash<Hash(ConvertibleTo<Key> const&&)>(), "");
+}
+
+
+template <class First, class ...Rest>
+struct TypeList<First, Rest...> {
+  template <template <class> class Trait, bool Expect = true>
+  static constexpr bool assertTrait() {
+    static_assert(Trait<First>::value == Expect, "");
+    return TypeList<Rest...>::template assertTrait<Trait, Expect>();
+  }
+
+  template <class Trait>
+  static void applyTrait() {
+    Trait::template apply<First>();
+    TypeList<Rest...>::template applyTrait<Trait>();
+  }
+};
+
+template <>
+struct TypeList<> {
+  template <template <class> class Trait, bool Expect = true>
+  static constexpr bool assertTrait() {
+    return true;
+  }
+  template <class Trait>
+  static void applyTrait() {}
+};
+
+
+struct TestLibraryTrait {
+    template <class Type>
+    static void apply() { test_hash_enabled<std::hash<Type>, Type>(); }
+};
+
+template <class Types>
+void test_library_hash_specializations_available(Types) {
+  Types::template applyTrait<TestLibraryTrait >();
+}
+
+#endif // SUPPORT_POISONED_HASH_HELPER_HPP
diff --git a/libcxx/test/support/test.support/test_poisoned_hash_helper.pass.cpp b/libcxx/test/support/test.support/test_poisoned_hash_helper.pass.cpp
new file mode 100644 (file)
index 0000000..4dffae6
--- /dev/null
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// Test that the header `poisoned_hash_helper.hpp` doesn't include any
+// headers that provide hash<T> specializations. This is required so that the
+// 'test_library_hash_specializations_available()' function returns false
+// by default, unless a STL header providing hash has already been included.
+
+#include "poisoned_hash_helper.hpp"
+
+template <class T, size_t = sizeof(T)>
+constexpr bool is_complete_imp(int) { return true; }
+template <class> constexpr bool is_complete_imp(long) { return false; }
+template <class T> constexpr bool is_complete() { return is_complete_imp<T>(0); }
+
+template <class T> struct has_complete_hash {
+  enum { value = is_complete<std::hash<T> >() };
+};
+
+int main() {
+  static_assert(LibraryHashTypes::assertTrait<has_complete_hash, false>(), "");
+}
index 88cf153..324f21d 100644 (file)
        <tr><td><a href="http://wg21.link/P0508R0">P0508R0</a></td><td>LWG</td><td>Wording for GB 58 - structured bindings for node_handles</td><td>Issaquah</td><td></td><td></td></tr>
        <tr><td><a href="http://wg21.link/P0509R1">P0509R1</a></td><td>LWG</td><td>Updating “Restrictions on exception handling”</td><td>Issaquah</td><td><i>Nothing to do</i></td><td>n/a</td></tr>
        <tr><td><a href="http://wg21.link/P0510R0">P0510R0</a></td><td>LWG</td><td>Disallowing references, incomplete types, arrays, and empty variants</td><td>Issaquah</td><td>Complete</td><td>4.0</td></tr>
-       <tr><td><a href="http://wg21.link/P0513R0">P0513R0</a></td><td>LWG</td><td>Poisoning the Hash</td><td>Issaquah</td><td></td><td></td></tr>
+       <tr><td><a href="http://wg21.link/P0513R0">P0513R0</a></td><td>LWG</td><td>Poisoning the Hash</td><td>Issaquah</td><td>Complete</td><td>5.0</td></tr>
        <tr><td><a href="http://wg21.link/P0516R0">P0516R0</a></td><td>LWG</td><td>Clarify That shared_future’s Copy Operations have Wide Contracts</td><td>Issaquah</td><td>Complete</td><td>4.0</td></tr>
        <tr><td><a href="http://wg21.link/P0517R0">P0517R0</a></td><td>LWG</td><td>Make future_error Constructible</td><td>Issaquah</td><td>Complete</td><td>4.0</td></tr>
        <tr><td><a href="http://wg21.link/P0521R0">P0521R0</a></td><td>LWG</td><td>Proposed Resolution for CA 14 (shared_ptr use_count/unique)</td><td>Issaquah</td><td><i>Nothing to do</i></td><td>n/a</td></tr>