[libcxx] r260513 - Teach __hash_table how to handle unordered_map's __hash_value_type.

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 11 03:59:44 PST 2016


Author: ericwf
Date: Thu Feb 11 05:59:44 2016
New Revision: 260513

URL: http://llvm.org/viewvc/llvm-project?rev=260513&view=rev
Log:
Teach __hash_table how to handle unordered_map's __hash_value_type.

This patch is fairly large and contains a number of changes. The main change
is teaching '__hash_table' how to handle '__hash_value_type'. Unfortunately
this change is a rampant layering violation, but it's required to make
unordered_map conforming without re-writing all of __hash_table.
After this change 'unordered_map' can delegate to '__hash_table' in almost all cases.

The major changes found in this patch are:

  * Teach __hash_table to differentiate between the true container value type
    and the node value type by introducing the "__container_value_type" and
    "__node_value_type" typedefs. In the case of unordered_map '__container_value_type'
    is 'pair<const Key, Value>' and '__node_value_type' is '__hash_value_type'.
    
  * Switch almost all overloads in '__hash_table' previously taking 'value_type'
    (AKA '__node_value_type) to take  '__container_value_type' instead. Previously
    'pair<K, V>' would be implicitly converted to '__hash_value_type<K, V>' because
    of the function signature.
    
  * Add '__get_key', '__get_value', '__get_ptr', and '__move' static functions to
    '__key_value_types'. These functions allow '__hash_table' to unwrap
    '__node_value_type' objects into '__container_value_type' and its sub-parts.

  * Pass  '__hash_value_type::__value_'  to 'a.construct(p, ...)' instead of
    '__hash_value_type' itself. The C++14 standard requires that 'a.construct()'
    and 'a.destroy()' are only ever instantiated for the containers value type.

  * Remove '__hash_value_type's constructors and destructors. We should never
    construct an instance of this type.
    (TODO this is UB but we already do it in plenty of places).
  
  * Add a generic "try-emplace" function to '__hash_table' called
    '__emplace_unique_key_args(Key const&, Args...)'.

  
The following changes were done as cleanup:

  * Introduce the '_LIBCPP_CXX03_LANG' macro to be used in place of
    '_LIBCPP_HAS_NO_VARIADICS' or '_LIBCPP_HAS_NO_RVALUE_REFERENCE'.
    
  * Cleanup C++11 only overloads that assume an incomplete C++11 implementation.
    For example this patch removes the __construct_node overloads that do
    manual pack expansion.
    
  * Forward 'unordered_map::emplace' to '__hash_table' and remove dead code
    resulting from the change. This includes almost all
    'unordered_map::__construct_node' overloads.


The following changes are planed for future revisions:

  * Fix LWG issue #2469 by delegating 'unordered_map::operator[]' to use
    '__emplace_unique_key_args'.
    
  * Rewrite 'unordered_map::try_emplace' in terms of '__emplace_unique_key_args'.
  
  * Optimize '__emplace_unique' to call '__emplace_unique_key_args' when possible.
    This prevent unneeded allocations when inserting duplicate entries.


The additional follow up work needed after this patch:

  * Respect the lifetime rules for '__hash_value_type' by actually constructing it.
  * Make '__insert_multi' act similar to '__insert_unique' for objects of type
    'T&' and 'T const &&' with 'T = __container_value_type'.
  
  

Added:
    libcxx/trunk/test/std/containers/unord/unord.map/unord.map.modifiers/insert_allocator_requirements.pass.cpp
    libcxx/trunk/test/std/containers/unord/unord.multimap/unord.multimap.modifiers/insert_allocator_requirements.pass.cpp
    libcxx/trunk/test/std/containers/unord/unord.multiset/insert_allocator_requirements.pass.cpp
    libcxx/trunk/test/std/containers/unord/unord.set/insert_allocator_requirements.pass.cpp
    libcxx/trunk/test/support/container_test_types.h
Modified:
    libcxx/trunk/include/__config
    libcxx/trunk/include/__hash_table
    libcxx/trunk/include/type_traits
    libcxx/trunk/include/unordered_map

Modified: libcxx/trunk/include/__config
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__config?rev=260513&r1=260512&r2=260513&view=diff
==============================================================================
--- libcxx/trunk/include/__config (original)
+++ libcxx/trunk/include/__config Thu Feb 11 05:59:44 2016
@@ -475,8 +475,6 @@ namespace std {
 #define _LIBCPP_NO_EXCEPTIONS
 #endif
 
-#define _LIBCPP_HAS_NO_TEMPLATE_ALIASES
-
 // constexpr was added to GCC in 4.6.
 #if _GNUC_VER < 406
 #define _LIBCPP_HAS_NO_CONSTEXPR
@@ -508,6 +506,7 @@ namespace std {
 #define _LIBCPP_HAS_NO_VARIADICS
 #define _LIBCPP_HAS_NO_RVALUE_REFERENCES
 #define _LIBCPP_HAS_NO_STRONG_ENUMS
+#define _LIBCPP_HAS_NO_TEMPLATE_ALIASES
 #define _LIBCPP_HAS_NO_NOEXCEPT
 
 #else  // __GXX_EXPERIMENTAL_CXX0X__
@@ -531,6 +530,7 @@ namespace std {
 #if _GNUC_VER < 406
 #define _LIBCPP_HAS_NO_NOEXCEPT
 #define _LIBCPP_HAS_NO_NULLPTR
+#define _LIBCPP_HAS_NO_TEMPLATE_ALIASES
 #endif
 
 #if _GNUC_VER < 407
@@ -849,7 +849,15 @@ extern "C" void __sanitizer_annotate_con
 
 #ifndef _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK
 #define _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK
-#endif 
+#endif
+
+#if __cplusplus < 201103L
+#define _LIBCPP_CXX03_LANG
+#else
+#if defined(_LIBCPP_HAS_NO_VARIADIC_TEMPLATES) || defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES)
+#error Libc++ requires a feature complete C++11 compiler in C++11 or greater.
+#endif
+#endif
 
 #endif // __cplusplus
 

Modified: libcxx/trunk/include/__hash_table
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__hash_table?rev=260513&r1=260512&r2=260513&view=diff
==============================================================================
--- libcxx/trunk/include/__hash_table (original)
+++ libcxx/trunk/include/__hash_table Thu Feb 11 05:59:44 2016
@@ -30,6 +30,29 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+
+#ifndef _LIBCPP_CXX03_LANG
+template <class _Key, class _Tp>
+union __hash_value_type;
+#else
+template <class _Key, class _Tp>
+struct __hash_value_type;
+#endif
+
+#ifndef _LIBCPP_CXX03_LANG
+template <class _Tp>
+struct __is_hash_value_type_imp : false_type {};
+
+template <class _Key, class _Value>
+struct __is_hash_value_type_imp<__hash_value_type<_Key, _Value>> : true_type {};
+
+template <class ..._Args>
+struct __is_hash_value_type : false_type {};
+
+template <class _One>
+struct __is_hash_value_type<_One> : __is_hash_value_type_imp<typename __uncvref<_One>::type> {};
+#endif
+
 _LIBCPP_FUNC_VIS
 size_t __next_prime(size_t __n);
 
@@ -86,14 +109,6 @@ template <class _ConstNodePtr> class _LI
 template <class _HashIterator> class _LIBCPP_TYPE_VIS_ONLY __hash_map_iterator;
 template <class _HashIterator> class _LIBCPP_TYPE_VIS_ONLY __hash_map_const_iterator;
 
-#if __cplusplus >= 201103L
-template <class _Key, class _Tp>
-union __hash_value_type;
-#else
-template <class _Key, class _Tp>
-struct __hash_value_type;
-#endif
-
 template <class _Tp>
 struct __key_value_types {
   static_assert(!is_reference<_Tp>::value && !is_const<_Tp>::value, "");
@@ -101,6 +116,25 @@ struct __key_value_types {
   typedef _Tp __node_value_type;
   typedef _Tp __container_value_type;
   static const bool __is_map = false;
+
+  _LIBCPP_INLINE_VISIBILITY
+  static key_type const& __get_key(_Tp const& __v) {
+    return __v;
+  }
+  _LIBCPP_INLINE_VISIBILITY
+  static __container_value_type const& __get_value(__node_value_type const& __v) {
+    return __v;
+  }
+  _LIBCPP_INLINE_VISIBILITY
+  static __container_value_type* __get_ptr(__node_value_type& __n) {
+    return _VSTD::addressof(__n);
+  }
+#ifndef _LIBCPP_CXX03_LANG
+  _LIBCPP_INLINE_VISIBILITY
+  static  __container_value_type&& __move(__node_value_type& __v) {
+    return _VSTD::move(__v);
+  }
+#endif
 };
 
 template <class _Key, class _Tp>
@@ -109,8 +143,42 @@ struct __key_value_types<__hash_value_ty
   typedef _Tp                                          mapped_type;
   typedef __hash_value_type<_Key, _Tp>                 __node_value_type;
   typedef pair<const _Key, _Tp>                        __container_value_type;
+  typedef pair<_Key, _Tp>                              __nc_value_type;
   typedef __container_value_type                       __map_value_type;
   static const bool __is_map = true;
+
+  _LIBCPP_INLINE_VISIBILITY
+  static key_type const& __get_key(__container_value_type const& __v) {
+    return __v.first;
+  }
+
+  template <class _Up>
+  _LIBCPP_INLINE_VISIBILITY
+  static typename enable_if<__is_same_uncvref<_Up, __node_value_type>::value,
+      __container_value_type const&>::type
+  __get_value(_Up& __t) {
+    return __t.__cc;
+  }
+
+  template <class _Up>
+  _LIBCPP_INLINE_VISIBILITY
+  static typename enable_if<__is_same_uncvref<_Up, __container_value_type>::value,
+      __container_value_type const&>::type
+  __get_value(_Up& __t) {
+    return __t;
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  static __container_value_type* __get_ptr(__node_value_type& __n) {
+    return _VSTD::addressof(__n.__cc);
+  }
+#ifndef _LIBCPP_CXX03_LANG
+  _LIBCPP_INLINE_VISIBILITY
+  static __nc_value_type&& __move(__node_value_type& __v) {
+    return _VSTD::move(__v.__nc);
+  }
+#endif
+
 };
 
 template <class _Tp, class _AllocPtr, class _KVTypes = __key_value_types<_Tp>,
@@ -787,6 +855,7 @@ class __hash_node_destructor
 public:
     typedef typename __alloc_traits::pointer                pointer;
 private:
+    typedef __hash_node_types<pointer> _NodeTypes;
 
     allocator_type& __na_;
 
@@ -806,7 +875,7 @@ public:
     void operator()(pointer __p) _NOEXCEPT
     {
         if (__value_constructed)
-            __alloc_traits::destroy(__na_, _VSTD::addressof(__p->__value_));
+            __alloc_traits::destroy(__na_, _NodeTypes::__get_ptr(__p->__value_));
         if (__p)
             __alloc_traits::deallocate(__na_, __p, 1);
     }
@@ -829,6 +898,9 @@ private:
       __make_hash_node_types<value_type, typename __alloc_traits::void_pointer>::type
                                                                      _NodeTypes;
 public:
+
+    typedef typename _NodeTypes::__node_value_type           __node_value_type;
+    typedef typename _NodeTypes::__container_value_type      __container_value_type;
     typedef value_type&                              reference;
     typedef const value_type&                        const_reference;
     typedef typename __alloc_traits::pointer         pointer;
@@ -925,7 +997,7 @@ public:
     explicit __hash_table(const allocator_type& __a);
     __hash_table(const __hash_table& __u);
     __hash_table(const __hash_table& __u, const allocator_type& __a);
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
+#ifndef _LIBCPP_CXX03_LANG
     __hash_table(__hash_table&& __u)
         _NOEXCEPT_(
             is_nothrow_move_constructible<__bucket_list>::value &&
@@ -934,11 +1006,11 @@ public:
             is_nothrow_move_constructible<hasher>::value &&
             is_nothrow_move_constructible<key_equal>::value);
     __hash_table(__hash_table&& __u, const allocator_type& __a);
-#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+#endif  // _LIBCPP_CXX03_LANG
     ~__hash_table();
 
     __hash_table& operator=(const __hash_table& __u);
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
+#ifndef _LIBCPP_CXX03_LANG
     _LIBCPP_INLINE_VISIBILITY
     __hash_table& operator=(__hash_table&& __u)
         _NOEXCEPT_(
@@ -964,41 +1036,56 @@ public:
     iterator             __node_insert_multi(const_iterator __p,
                                              __node_pointer __nd);
 
-#if !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS)
+#ifndef _LIBCPP_CXX03_LANG
+    template <class _Key, class ..._Args>
+    pair<iterator, bool> __emplace_unique_key_args(_Key const& __k, _Args&&... __args);
+
     template <class... _Args>
-        pair<iterator, bool> __emplace_unique(_Args&&... __args);
+    pair<iterator, bool> __emplace_unique(_Args&&... __args);
     template <class... _Args>
-        iterator __emplace_multi(_Args&&... __args);
+    iterator __emplace_multi(_Args&&... __args);
     template <class... _Args>
-        iterator __emplace_hint_multi(const_iterator __p, _Args&&... __args);
-#endif  // !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS)
+    iterator __emplace_hint_multi(const_iterator __p, _Args&&... __args);
+
 
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
-    template <class _ValueTp>
-    _LIBCPP_INLINE_VISIBILITY
-    pair<iterator, bool> __insert_unique_value(_ValueTp&& __x);
-#else
     _LIBCPP_INLINE_VISIBILITY
-    pair<iterator, bool> __insert_unique_value(const value_type& __x);
-#endif
+    pair<iterator, bool>
+    __insert_unique(__container_value_type&& __x) {
+      return __emplace_unique_key_args(_NodeTypes::__get_key(__x), _VSTD::move(__x));
+    }
 
-    pair<iterator, bool> __insert_unique(const value_type& __x);
+    template <class _Pp, class = typename enable_if<
+            !__is_same_uncvref<_Pp, __container_value_type>::value
+        >::type>
+    _LIBCPP_INLINE_VISIBILITY
+    pair<iterator, bool> __insert_unique(_Pp&& __x) {
+      return __emplace_unique(_VSTD::forward<_Pp>(__x));
+    }
 
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
-    pair<iterator, bool> __insert_unique(value_type&& __x);
     template <class _Pp>
-    pair<iterator, bool> __insert_unique(_Pp&& __x);
-#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+    _LIBCPP_INLINE_VISIBILITY
+    iterator __insert_multi(_Pp&& __x) {
+      return __emplace_multi(_VSTD::forward<_Pp>(__x));
+    }
 
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
-    template <class _Pp>
-        iterator __insert_multi(_Pp&& __x);
     template <class _Pp>
-        iterator __insert_multi(const_iterator __p, _Pp&& __x);
-#else  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
-    iterator __insert_multi(const value_type& __x);
-    iterator __insert_multi(const_iterator __p, const value_type& __x);
-#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+    _LIBCPP_INLINE_VISIBILITY
+    iterator __insert_multi(const_iterator __p, _Pp&& __x) {
+        return __emplace_hint_multi(__p, _VSTD::forward<_Pp>(__x));
+    }
+
+#else  // !defined(_LIBCPP_CXX03_LANG)
+    template <class _Key, class _Args>
+    pair<iterator, bool> __emplace_unique_key_args(_Key const&, _Args& __args);
+
+    iterator __insert_multi(const __container_value_type& __x);
+    iterator __insert_multi(const_iterator __p, const __container_value_type& __x);
+#endif
+
+    _LIBCPP_INLINE_VISIBILITY
+    pair<iterator, bool> __insert_unique(const __container_value_type& __x) {
+        return __emplace_unique_key_args(_NodeTypes::__get_key(__x), __x);
+    }
 
     void clear() _NOEXCEPT;
     void rehash(size_type __n);
@@ -1158,17 +1245,17 @@ public:
 private:
     void __rehash(size_type __n);
 
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
-#ifndef _LIBCPP_HAS_NO_VARIADICS
+#ifndef _LIBCPP_CXX03_LANG
     template <class ..._Args>
-        __node_holder __construct_node(_Args&& ...__args);
-#endif  // _LIBCPP_HAS_NO_VARIADICS
-    template <class _ValueTp>
-    __node_holder __construct_node_hash(_ValueTp&& __v, size_t __hash);
-#else  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
-    __node_holder __construct_node(const value_type& __v);
+    __node_holder __construct_node(_Args&& ...__args);
+
+    template <class _First, class ..._Rest>
+    __node_holder __construct_node_hash(size_t __hash, _First&& __f, _Rest&&... __rest);
+#else // _LIBCPP_CXX03_LANG
+    __node_holder __construct_node(const __container_value_type& __v);
+    __node_holder __construct_node_hash(size_t __hash, const __container_value_type& __v);
 #endif
-    __node_holder __construct_node_hash(const value_type& __v, size_t __hash);
+
 
     _LIBCPP_INLINE_VISIBILITY
     void __copy_assign_alloc(const __hash_table& __u)
@@ -1178,6 +1265,7 @@ private:
     _LIBCPP_INLINE_VISIBILITY
         void __copy_assign_alloc(const __hash_table&, false_type) {}
 
+#ifndef _LIBCPP_CXX03_LANG
     void __move_assign(__hash_table& __u, false_type);
     void __move_assign(__hash_table& __u, true_type)
         _NOEXCEPT_(
@@ -1204,6 +1292,7 @@ private:
     }
     _LIBCPP_INLINE_VISIBILITY
         void __move_assign_alloc(__hash_table&, false_type) _NOEXCEPT {}
+#endif // _LIBCPP_CXX03_LANG
 
     void __deallocate(__node_pointer __np) _NOEXCEPT;
     __node_pointer __detach() _NOEXCEPT;
@@ -1280,7 +1369,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>
 {
 }
 
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
+#ifndef _LIBCPP_CXX03_LANG
 
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(__hash_table&& __u)
@@ -1329,7 +1418,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>
     }
 }
 
-#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+#endif  // _LIBCPP_CXX03_LANG
 
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 __hash_table<_Tp, _Hash, _Equal, _Alloc>::~__hash_table()
@@ -1394,7 +1483,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>
         }
         __get_db()->unlock();
 #endif
-        __node_traits::destroy(__na, _VSTD::addressof(__np->__value_));
+        __node_traits::destroy(__na, _NodeTypes::__get_ptr(__np->__value_));
         __node_traits::deallocate(__na, __np, 1);
         __np = __next;
     }
@@ -1413,7 +1502,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>
     return __cache;
 }
 
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
+#ifndef _LIBCPP_CXX03_LANG
 
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 void
@@ -1486,8 +1575,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>
         const_iterator __i = __u.begin();
         while (__u.size() != 0)
         {
-            __node_holder __h =
-                    __construct_node(_VSTD::move(__u.remove(__i++)->__value_));
+            __node_holder __h = __construct_node(_NodeTypes::__move(__u.remove(__i++)->__value_));
             __node_insert_multi(__h.get());
             __h.release();
         }
@@ -1509,7 +1597,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>
     return *this;
 }
 
-#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+#endif  // _LIBCPP_CXX03_LANG
 
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 template <class _InputIterator>
@@ -1517,6 +1605,11 @@ void
 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_unique(_InputIterator __first,
                                                           _InputIterator __last)
 {
+    typedef iterator_traits<_InputIterator> _ITraits;
+    typedef typename _ITraits::value_type _ItValueType;
+    static_assert((is_same<_ItValueType, __container_value_type>::value),
+                  "__assign_unique may only be called with the containers value type");
+
     if (bucket_count() != 0)
     {
         __node_pointer __cache = __detach();
@@ -1551,6 +1644,12 @@ void
 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_multi(_InputIterator __first,
                                                          _InputIterator __last)
 {
+    typedef iterator_traits<_InputIterator> _ITraits;
+    typedef typename _ITraits::value_type _ItValueType;
+    static_assert((is_same<_ItValueType, __container_value_type>::value ||
+                  is_same<_ItValueType, __node_value_type>::value),
+                  "__assign_multi may only be called with the containers value type"
+                  " or the nodes value type");
     if (bucket_count() != 0)
     {
         __node_pointer __cache = __detach();
@@ -1576,7 +1675,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>
         __deallocate(__cache);
     }
     for (; __first != __last; ++__first)
-        __insert_multi(*__first);
+        __insert_multi(_NodeTypes::__get_value(*__first));
 }
 
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
@@ -1802,31 +1901,24 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>
     return __node_insert_multi(__cp);
 }
 
-template <class _Tp, class _Hash, class _Equal, class _Alloc>
-pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator, bool>
-__hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_unique(const value_type& __x)
-{
-    return __insert_unique_value(__x);
-}
 
 
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
+#ifndef _LIBCPP_CXX03_LANG
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
-template <class _ValueTp>
+template <class _Key, class ..._Args>
 _LIBCPP_INLINE_VISIBILITY
 pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator, bool>
-__hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_unique_value(_ValueTp&& __x)
+__hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_unique_key_args(_Key const& __k, _Args&&... __args)
 #else
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
+template <class _Key, class _Args>
 _LIBCPP_INLINE_VISIBILITY
 pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator, bool>
-__hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_unique_value(const value_type& __x)
+__hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_unique_key_args(_Key const& __k, _Args& __args)
 #endif
 {
-#if defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES)
-    typedef const value_type& _ValueTp;
-#endif
-    size_t __hash = hash_function()(__x);
+
+    size_t __hash = hash_function()(__k);
     size_type __bc = bucket_count();
     bool __inserted = false;
     __node_pointer __nd;
@@ -1841,13 +1933,17 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>
                                        __constrain_hash(__nd->__hash_, __bc) == __chash;
                                                            __nd = __nd->__next_)
             {
-                if (key_eq()(__nd->__value_, __x))
+                if (key_eq()(__nd->__value_, __k))
                     goto __done;
             }
         }
     }
     {
-        __node_holder __h = __construct_node_hash(_VSTD::forward<_ValueTp>(__x), __hash);
+#ifndef _LIBCPP_CXX03_LANG
+        __node_holder __h = __construct_node_hash(__hash, _VSTD::forward<_Args>(__args)...);
+#else
+        __node_holder __h = __construct_node_hash(__hash, __args);
+#endif
         if (size()+1 > __bc * max_load_factor() || __bc == 0)
         {
             rehash(_VSTD::max<size_type>(2 * __bc + !__is_hash_power2(__bc),
@@ -1885,8 +1981,7 @@ __done:
 #endif
 }
 
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
-#ifndef _LIBCPP_HAS_NO_VARIADICS
+#ifndef _LIBCPP_CXX03_LANG
 
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 template <class... _Args>
@@ -1928,64 +2023,11 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>
     return __r;
 }
 
-#endif  // _LIBCPP_HAS_NO_VARIADICS
-
-template <class _Tp, class _Hash, class _Equal, class _Alloc>
-pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator, bool>
-__hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_unique(value_type&& __x)
-{
-    return __insert_unique_value(_VSTD::move(__x));
-}
-
-template <class _Tp, class _Hash, class _Equal, class _Alloc>
-template <class _Pp>
-pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator, bool>
-__hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_unique(_Pp&& __x)
-{
-    __node_holder __h = __construct_node(_VSTD::forward<_Pp>(__x));
-    pair<iterator, bool> __r = __node_insert_unique(__h.get());
-    if (__r.second)
-        __h.release();
-    return __r;
-}
-
-#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
-
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
-
-template <class _Tp, class _Hash, class _Equal, class _Alloc>
-template <class _Pp>
-typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
-__hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_multi(_Pp&& __x)
-{
-    __node_holder __h = __construct_node(_VSTD::forward<_Pp>(__x));
-    iterator __r = __node_insert_multi(__h.get());
-    __h.release();
-    return __r;
-}
-
-template <class _Tp, class _Hash, class _Equal, class _Alloc>
-template <class _Pp>
-typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
-__hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_multi(const_iterator __p,
-                                                         _Pp&& __x)
-{
-#if _LIBCPP_DEBUG_LEVEL >= 2
-    _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__p) == this,
-        "unordered container::insert(const_iterator, rvalue) called with an iterator not"
-        " referring to this unordered container");
-#endif
-    __node_holder __h = __construct_node(_VSTD::forward<_Pp>(__x));
-    iterator __r = __node_insert_multi(__p, __h.get());
-    __h.release();
-    return __r;
-}
-
-#else  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+#else // _LIBCPP_CXX03_LANG
 
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
-__hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_multi(const value_type& __x)
+__hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_multi(const __container_value_type& __x)
 {
     __node_holder __h = __construct_node(__x);
     iterator __r = __node_insert_multi(__h.get());
@@ -1996,7 +2038,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_multi(const_iterator __p,
-                                                         const value_type& __x)
+                                                         const __container_value_type& __x)
 {
 #if _LIBCPP_DEBUG_LEVEL >= 2
     _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__p) == this,
@@ -2009,7 +2051,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>
     return __r;
 }
 
-#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+#endif  // _LIBCPP_CXX03_LANG
 
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 void
@@ -2148,71 +2190,74 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>
     return end();
 }
 
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
-#ifndef _LIBCPP_HAS_NO_VARIADICS
+#ifndef _LIBCPP_CXX03_LANG
 
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 template <class ..._Args>
 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder
 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node(_Args&& ...__args)
 {
+    static_assert(!__is_hash_value_type<_Args...>::value,
+                  "Construct cannot be called with a hash value type");
     __node_allocator& __na = __node_alloc();
     __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
-    __node_traits::construct(__na, _VSTD::addressof(__h->__value_), _VSTD::forward<_Args>(__args)...);
+    __node_traits::construct(__na, _NodeTypes::__get_ptr(__h->__value_), _VSTD::forward<_Args>(__args)...);
     __h.get_deleter().__value_constructed = true;
     __h->__hash_ = hash_function()(__h->__value_);
     __h->__next_ = nullptr;
     return __h;
 }
 
-#endif  // _LIBCPP_HAS_NO_VARIADICS
-
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
-template <class _ValueTp>
+template <class _First, class ..._Rest>
 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder
-__hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node_hash(_ValueTp&& __v,
-                                                                size_t __hash)
+__hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node_hash(
+    size_t __hash, _First&& __f, _Rest&& ...__rest)
 {
+    static_assert(!__is_hash_value_type<_First, _Rest...>::value,
+                  "Construct cannot be called with a hash value type");
     __node_allocator& __na = __node_alloc();
     __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
-    __node_traits::construct(__na, _VSTD::addressof(__h->__value_), _VSTD::forward<_ValueTp>(__v));
+    __node_traits::construct(__na, _NodeTypes::__get_ptr(__h->__value_),
+                             _VSTD::forward<_First>(__f),
+                             _VSTD::forward<_Rest>(__rest)...);
     __h.get_deleter().__value_constructed = true;
     __h->__hash_ = __hash;
     __h->__next_ = nullptr;
     return __h;
 }
 
-#else  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+#else  // _LIBCPP_CXX03_LANG
 
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder
-__hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node(const value_type& __v)
+__hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node(const __container_value_type& __v)
 {
     __node_allocator& __na = __node_alloc();
     __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
-    __node_traits::construct(__na, _VSTD::addressof(__h->__value_), __v);
+    __node_traits::construct(__na, _NodeTypes::__get_ptr(__h->__value_), __v);
     __h.get_deleter().__value_constructed = true;
     __h->__hash_ = hash_function()(__h->__value_);
     __h->__next_ = nullptr;
     return _LIBCPP_EXPLICIT_MOVE(__h);  // explicitly moved for C++03
 }
 
-#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
-
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder
-__hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node_hash(const value_type& __v,
-                                                                size_t __hash)
+__hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node_hash(size_t __hash,
+                                                                const __container_value_type& __v)
 {
     __node_allocator& __na = __node_alloc();
     __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
-    __node_traits::construct(__na, _VSTD::addressof(__h->__value_), __v);
+    __node_traits::construct(__na, _NodeTypes::__get_ptr(__h->__value_), __v);
     __h.get_deleter().__value_constructed = true;
     __h->__hash_ = __hash;
     __h->__next_ = nullptr;
     return _LIBCPP_EXPLICIT_MOVE(__h);  // explicitly moved for C++03
 }
 
+#endif  // _LIBCPP_CXX03_LANG
+
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
 __hash_table<_Tp, _Hash, _Equal, _Alloc>::erase(const_iterator __p)

Modified: libcxx/trunk/include/type_traits
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/type_traits?rev=260513&r1=260512&r2=260513&view=diff
==============================================================================
--- libcxx/trunk/include/type_traits (original)
+++ libcxx/trunk/include/type_traits Thu Feb 11 05:59:44 2016
@@ -1091,6 +1091,12 @@ struct __uncvref  {
     typedef typename remove_cv<typename remove_reference<_Tp>::type>::type type;
 };
 
+// __is_same_uncvref
+
+template <class _Tp, class _Up>
+struct __is_same_uncvref : is_same<typename __uncvref<_Tp>::type,
+                                   typename __uncvref<_Up>::type> {};
+
 struct __any
 {
     __any(...);

Modified: libcxx/trunk/include/unordered_map
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/unordered_map?rev=260513&r1=260512&r2=260513&view=diff
==============================================================================
--- libcxx/trunk/include/unordered_map (original)
+++ libcxx/trunk/include/unordered_map Thu Feb 11 05:59:44 2016
@@ -583,8 +583,7 @@ public:
     }
 };
 
-#if __cplusplus >= 201103L
-
+#ifndef _LIBCPP_CXX03_LANG
 template <class _Key, class _Tp>
 union __hash_value_type
 {
@@ -596,19 +595,6 @@ union __hash_value_type
     value_type __cc;
     __nc_value_type __nc;
 
-    template <class ..._Args>
-    _LIBCPP_INLINE_VISIBILITY
-    __hash_value_type(_Args&& ...__args)
-        : __cc(std::forward<_Args>(__args)...) {}
-
-    _LIBCPP_INLINE_VISIBILITY
-    __hash_value_type(const __hash_value_type& __v)
-        : __cc(__v.__cc) {}
-
-    _LIBCPP_INLINE_VISIBILITY
-    __hash_value_type(__hash_value_type&& __v)
-        : __nc(_VSTD::move(__v.__nc)) {}
-
     _LIBCPP_INLINE_VISIBILITY
     __hash_value_type& operator=(const __hash_value_type& __v)
         {__nc = __v.__cc; return *this;}
@@ -617,8 +603,23 @@ union __hash_value_type
     __hash_value_type& operator=(__hash_value_type&& __v)
         {__nc = _VSTD::move(__v.__nc); return *this;}
 
+    template <class _ValueTp,
+              class = typename enable_if<
+                    __is_same_uncvref<_ValueTp, value_type>::value
+                 >::type
+             >
     _LIBCPP_INLINE_VISIBILITY
-    ~__hash_value_type() {__cc.~value_type();}
+    __hash_value_type& operator=(_ValueTp&& __v) {
+        __nc = _VSTD::forward<_ValueTp>(__v); return *this;
+    }
+
+private:
+    __hash_value_type(const __hash_value_type& __v) = delete;
+    __hash_value_type(__hash_value_type&& __v) = delete;
+    template <class ..._Args>
+    explicit __hash_value_type(_Args&& ...__args) = delete;
+
+    ~__hash_value_type() = delete;
 };
 
 #else
@@ -632,18 +633,8 @@ struct __hash_value_type
 
     value_type __cc;
 
-    _LIBCPP_INLINE_VISIBILITY
-    __hash_value_type() {}
-
-    template <class _A0>
-    _LIBCPP_INLINE_VISIBILITY
-    __hash_value_type(const _A0& __a0)
-        : __cc(__a0) {}
-
-    template <class _A0, class _A1>
-    _LIBCPP_INLINE_VISIBILITY
-    __hash_value_type(const _A0& __a0, const _A1& __a1)
-        : __cc(__a0, __a1) {}
+private:
+   ~__hash_value_type();
 };
 
 #endif
@@ -780,6 +771,7 @@ private:
 
     __table __table_;
 
+    typedef typename __table::_NodeTypes                   _NodeTypes;
     typedef typename __table::__node_pointer               __node_pointer;
     typedef typename __table::__node_const_pointer         __node_const_pointer;
     typedef typename __table::__node_traits                __node_traits;
@@ -788,6 +780,9 @@ private:
     typedef __hash_map_node_destructor<__node_allocator>   _Dp;
     typedef unique_ptr<__node, _Dp>                         __node_holder;
     typedef allocator_traits<allocator_type>               __alloc_traits;
+
+    static_assert((is_same<typename __table::__container_value_type, value_type>::value), "");
+    static_assert((is_same<typename __table::__node_value_type, __value_type>::value), "");
 public:
     typedef typename __alloc_traits::pointer         pointer;
     typedef typename __alloc_traits::const_pointer   const_pointer;
@@ -913,28 +908,26 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     const_iterator cend()   const _NOEXCEPT {return __table_.end();}
 
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
-#ifndef _LIBCPP_HAS_NO_VARIADICS
-
+#ifndef _LIBCPP_CXX03_LANG
     template <class... _Args>
-        pair<iterator, bool> emplace(_Args&&... __args);
+    _LIBCPP_INLINE_VISIBILITY
+    pair<iterator, bool> emplace(_Args&&... __args) {
+        return __table_.__emplace_unique(_VSTD::forward<_Args>(__args)...);
+    }
 
     template <class... _Args>
-        _LIBCPP_INLINE_VISIBILITY
+    _LIBCPP_INLINE_VISIBILITY
+    iterator emplace_hint(const_iterator __p, _Args&&... __args) {
 #if _LIBCPP_DEBUG_LEVEL >= 2
-        iterator emplace_hint(const_iterator __p, _Args&&... __args)
-        {
-            _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__p) == this,
-                "unordered_map::emplace_hint(const_iterator, args...) called with an iterator not"
-                " referring to this unordered_map");
-            return __table_.__emplace_unique(_VSTD::forward<_Args>(__args)...).first;
-        }
-#else
-        iterator emplace_hint(const_iterator, _Args&&... __args)
-            {return emplace(_VSTD::forward<_Args>(__args)...).first;}
+        _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__p) == this,
+            "unordered_map::emplace_hint(const_iterator, args...) called with an iterator not"
+            " referring to this unordered_map");
 #endif
-#endif  // _LIBCPP_HAS_NO_VARIADICS
-#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+        return __table_.__emplace_unique(_VSTD::forward<_Args>(__args)...).first;
+    }
+
+#endif // _LIBCPP_CXX03_LANG
+
     _LIBCPP_INLINE_VISIBILITY
     pair<iterator, bool> insert(const value_type& __x)
         {return __table_.__insert_unique(__x);}
@@ -1191,17 +1184,9 @@ public:
 #endif  // _LIBCPP_DEBUG_LEVEL >= 2
 
 private:
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
-    __node_holder __construct_node();
-    template <class _A0>
-        __node_holder
-         __construct_node(_A0&& __a0);
+#ifndef _LIBCPP_CXX03_LANG
     __node_holder __construct_node_with_key(key_type&& __k);
-#ifndef _LIBCPP_HAS_NO_VARIADICS
-    template <class _A0, class _A1, class ..._Args>
-        __node_holder __construct_node(_A0&& __a0, _A1&& __a1, _Args&& ...__args);
-#endif  // _LIBCPP_HAS_NO_VARIADICS
-#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+#endif  // _LIBCPP_CXX03_LANG
     __node_holder __construct_node_with_key(const key_type& __k);
 };
 
@@ -1328,10 +1313,10 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _
     if (__a != __u.get_allocator())
     {
         iterator __i = __u.begin();
-        while (__u.size() != 0)
-            __table_.__insert_unique(
-                _VSTD::move(__u.__table_.remove((__i++).__i_)->__value_)
-                                    );
+        while (__u.size() != 0) {
+            __table_.__emplace_unique(_VSTD::move(
+                __u.__table_.remove((__i++).__i_)->__value_.__nc));
+        }
     }
 #if _LIBCPP_DEBUG_LEVEL >= 2
     else
@@ -1409,33 +1394,7 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _
 
 #endif  // _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS
 
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
-
-template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
-typename unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder
-unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__construct_node()
-{
-    __node_allocator& __na = __table_.__node_alloc();
-    __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
-    __node_traits::construct(__na, _VSTD::addressof(__h->__value_));
-    __h.get_deleter().__first_constructed = true;
-    __h.get_deleter().__second_constructed = true;
-    return __h;
-}
-
-template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
-template <class _A0>
-typename unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder
-unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__construct_node(_A0&& __a0)
-{
-    __node_allocator& __na = __table_.__node_alloc();
-    __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
-    __node_traits::construct(__na, _VSTD::addressof(__h->__value_),
-                             _VSTD::forward<_A0>(__a0));
-    __h.get_deleter().__first_constructed = true;
-    __h.get_deleter().__second_constructed = true;
-    return __h;
-}
+#ifndef _LIBCPP_CXX03_LANG
 
 template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
 typename unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder
@@ -1450,39 +1409,7 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _
     return __h;
 }
 
-#ifndef _LIBCPP_HAS_NO_VARIADICS
-
-template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
-template <class _A0, class _A1, class ..._Args>
-typename unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder
-unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__construct_node(_A0&& __a0,
-                                                                 _A1&& __a1,
-                                                                 _Args&&... __args)
-{
-    __node_allocator& __na = __table_.__node_alloc();
-    __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
-    __node_traits::construct(__na, _VSTD::addressof(__h->__value_),
-                             _VSTD::forward<_A0>(__a0), _VSTD::forward<_A1>(__a1),
-                             _VSTD::forward<_Args>(__args)...);
-    __h.get_deleter().__first_constructed = true;
-    __h.get_deleter().__second_constructed = true;
-    return __h;
-}
-
-template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
-template <class... _Args>
-pair<typename unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::iterator, bool>
-unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::emplace(_Args&&... __args)
-{
-    __node_holder __h = __construct_node(_VSTD::forward<_Args>(__args)...);
-    pair<iterator, bool> __r = __table_.__node_insert_unique(__h.get());
-    if (__r.second)
-        __h.release();
-    return __r;
-}
-
-#endif  // _LIBCPP_HAS_NO_VARIADICS
-#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+#endif
 
 template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
 typename unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder
@@ -1630,6 +1557,7 @@ private:
 
     __table __table_;
 
+    typedef typename __table::_NodeTypes                   _NodeTypes;
     typedef typename __table::__node_traits                __node_traits;
     typedef typename __table::__node_allocator             __node_allocator;
     typedef typename __table::__node                       __node;
@@ -1765,16 +1693,18 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     const_iterator cend()   const _NOEXCEPT {return __table_.end();}
 
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
-#ifndef _LIBCPP_HAS_NO_VARIADICS
-
+#ifndef _LIBCPP_CXX03_LANG
     template <class... _Args>
-        iterator emplace(_Args&&... __args);
+    iterator emplace(_Args&&... __args) {
+        return __table_.__emplace_multi(_VSTD::forward<_Args>(__args)...);
+    }
 
     template <class... _Args>
-        iterator emplace_hint(const_iterator __p, _Args&&... __args);
-#endif  // _LIBCPP_HAS_NO_VARIADICS
-#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+    iterator emplace_hint(const_iterator __p, _Args&&... __args) {
+        return __table_.__emplace_hint_multi(__p.__i_, _VSTD::forward<_Args>(__args)...);
+    }
+#endif  // _LIBCPP_CXX03_LANG
+
     _LIBCPP_INLINE_VISIBILITY
     iterator insert(const value_type& __x) {return __table_.__insert_multi(__x);}
 #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
@@ -1888,17 +1818,7 @@ public:
 
 #endif  // _LIBCPP_DEBUG_LEVEL >= 2
 
-private:
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
-    __node_holder __construct_node();
-    template <class _A0>
-        __node_holder
-         __construct_node(_A0&& __a0);
-#ifndef _LIBCPP_HAS_NO_VARIADICS
-    template <class _A0, class _A1, class ..._Args>
-        __node_holder __construct_node(_A0&& __a0, _A1&& __a1, _Args&& ...__args);
-#endif  // _LIBCPP_HAS_NO_VARIADICS
-#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+
 };
 
 template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
@@ -2027,7 +1947,7 @@ unordered_multimap<_Key, _Tp, _Hash, _Pr
         while (__u.size() != 0)
         {
             __table_.__insert_multi(
-                _VSTD::move(__u.__table_.remove((__i++).__i_)->__value_)
+                      _VSTD::move(__u.__table_.remove((__i++).__i_)->__value_.__nc)
                                    );
         }
     }
@@ -2107,77 +2027,7 @@ unordered_multimap<_Key, _Tp, _Hash, _Pr
 
 #endif  // _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS
 
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
 
-template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
-typename unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder
-unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::__construct_node()
-{
-    __node_allocator& __na = __table_.__node_alloc();
-    __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
-    __node_traits::construct(__na, _VSTD::addressof(__h->__value_));
-    __h.get_deleter().__first_constructed = true;
-    __h.get_deleter().__second_constructed = true;
-    return __h;
-}
-
-template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
-template <class _A0>
-typename unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder
-unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::__construct_node(_A0&& __a0)
-{
-    __node_allocator& __na = __table_.__node_alloc();
-    __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
-    __node_traits::construct(__na, _VSTD::addressof(__h->__value_),
-                             _VSTD::forward<_A0>(__a0));
-    __h.get_deleter().__first_constructed = true;
-    __h.get_deleter().__second_constructed = true;
-    return __h;
-}
-
-#ifndef _LIBCPP_HAS_NO_VARIADICS
-
-template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
-template <class _A0, class _A1, class ..._Args>
-typename unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder
-unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::__construct_node(
-        _A0&& __a0, _A1&& __a1, _Args&&... __args)
-{
-    __node_allocator& __na = __table_.__node_alloc();
-    __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
-    __node_traits::construct(__na, _VSTD::addressof(__h->__value_),
-                             _VSTD::forward<_A0>(__a0), _VSTD::forward<_A1>(__a1),
-                             _VSTD::forward<_Args>(__args)...);
-    __h.get_deleter().__first_constructed = true;
-    __h.get_deleter().__second_constructed = true;
-    return __h;
-}
-
-template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
-template <class... _Args>
-typename unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::iterator
-unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::emplace(_Args&&... __args)
-{
-    __node_holder __h = __construct_node(_VSTD::forward<_Args>(__args)...);
-    iterator __r = __table_.__node_insert_multi(__h.get());
-    __h.release();
-    return __r;
-}
-
-template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
-template <class... _Args>
-typename unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::iterator
-unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::emplace_hint(
-        const_iterator __p, _Args&&... __args)
-{
-    __node_holder __h = __construct_node(_VSTD::forward<_Args>(__args)...);
-    iterator __r = __table_.__node_insert_multi(__p.__i_, __h.get());
-    __h.release();
-    return __r;
-}
-
-#endif  // _LIBCPP_HAS_NO_VARIADICS
-#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
 
 template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
 template <class _InputIterator>

Added: libcxx/trunk/test/std/containers/unord/unord.map/unord.map.modifiers/insert_allocator_requirements.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/unord/unord.map/unord.map.modifiers/insert_allocator_requirements.pass.cpp?rev=260513&view=auto
==============================================================================
--- libcxx/trunk/test/std/containers/unord/unord.map/unord.map.modifiers/insert_allocator_requirements.pass.cpp (added)
+++ libcxx/trunk/test/std/containers/unord/unord.map/unord.map.modifiers/insert_allocator_requirements.pass.cpp Thu Feb 11 05:59:44 2016
@@ -0,0 +1,143 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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.
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+
+// class unordered_map
+
+// insert(...);
+
+// UNSUPPORTED: c++98, c++03
+
+
+#include <unordered_map>
+#include <iostream>
+#include <cassert>
+
+#include "test_macros.h"
+#include "count_new.hpp"
+#include "container_test_types.h"
+
+#if TEST_STD_VER >= 11
+template <class Arg>
+void PrintInfo(int line, Arg&& arg)
+#else
+template <class Arg>
+void PrintInfo(int line, Arg arg)
+#endif
+{
+  std::cout << "In " << __FILE__ << ":" << line << ":\n    " << arg << "\n" << std::endl;
+}
+#define PRINT(...) PrintInfo(__LINE__, __VA_ARGS__)
+
+template <class Container>
+void testContainerInsert()
+{
+  typedef typename Container::value_type ValueTp;
+  typedef Container C;
+  typedef std::pair<typename C::iterator, bool> R;
+  ConstructController* cc = getConstructController();
+  cc->reset();
+  {
+    PRINT("Testing C::insert(const value_type&)");
+    Container c;
+    const ValueTp v(42, 1);
+    cc->expect<const ValueTp&>();
+    assert(c.insert(v).second);
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      const ValueTp v2(42, 1);
+      assert(c.insert(v2).second == false);
+    }
+  }
+  {
+    PRINT("Testing C::insert(value_type&)");
+    Container c;
+    ValueTp v(42, 1);
+    cc->expect<const ValueTp&>();
+    assert(c.insert(v).second);
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      ValueTp v2(42, 1);
+      assert(c.insert(v2).second == false);
+    }
+  }
+  {
+    PRINT("Testing C::insert(value_type&&)");
+    Container c;
+    ValueTp v(42, 1);
+    cc->expect<ValueTp&&>();
+    assert(c.insert(std::move(v)).second);
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      ValueTp v2(42, 1);
+      assert(c.insert(std::move(v2)).second == false);
+    }
+  }
+  {
+    PRINT("Testing C::insert(std::initializer_list<ValueTp>)");
+    Container c;
+    std::initializer_list<ValueTp> il = { ValueTp(1, 1), ValueTp(2, 1) };
+    cc->expect<ValueTp const&>(2);
+    c.insert(il);
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      c.insert(il);
+    }
+  }
+  {
+    PRINT("Testing C::insert(Iter, Iter) for *Iter = value_type const&");
+    Container c;
+    const ValueTp ValueList[] = { ValueTp(1, 1), ValueTp(2, 1), ValueTp(3, 1) };
+    cc->expect<ValueTp const&>(3);
+    c.insert(std::begin(ValueList), std::end(ValueList));
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      c.insert(std::begin(ValueList), std::end(ValueList));
+    }
+  }
+  {
+    PRINT("Testing C::insert(Iter, Iter) for *Iter = value_type&&");
+    Container c;
+    ValueTp ValueList[] = { ValueTp(1, 1), ValueTp(2, 1) , ValueTp(3, 1) };
+    cc->expect<ValueTp&&>(3);
+    c.insert(std::move_iterator<ValueTp*>(std::begin(ValueList)),
+             std::move_iterator<ValueTp*>(std::end(ValueList)));
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      ValueTp ValueList2[] = { ValueTp(1, 1), ValueTp(2, 1) , ValueTp(3, 1) };
+      c.insert(std::move_iterator<ValueTp*>(std::begin(ValueList2)),
+               std::move_iterator<ValueTp*>(std::end(ValueList2)));
+    }
+  }
+  {
+    PRINT("Testing C::insert(Iter, Iter) for *Iter = value_type&");
+    Container c;
+    ValueTp ValueList[] = { ValueTp(1, 1), ValueTp(2, 1) , ValueTp(3, 1) };
+    cc->expect<ValueTp const&>(3);
+    c.insert(std::begin(ValueList), std::end(ValueList));
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      c.insert(std::begin(ValueList), std::end(ValueList));
+    }
+  }
+}
+
+
+int main()
+{
+  testContainerInsert<TCT::unordered_map<> >();
+}

Added: libcxx/trunk/test/std/containers/unord/unord.multimap/unord.multimap.modifiers/insert_allocator_requirements.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/unord/unord.multimap/unord.multimap.modifiers/insert_allocator_requirements.pass.cpp?rev=260513&view=auto
==============================================================================
--- libcxx/trunk/test/std/containers/unord/unord.multimap/unord.multimap.modifiers/insert_allocator_requirements.pass.cpp (added)
+++ libcxx/trunk/test/std/containers/unord/unord.multimap/unord.multimap.modifiers/insert_allocator_requirements.pass.cpp Thu Feb 11 05:59:44 2016
@@ -0,0 +1,108 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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.
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+
+// class unordered_multimap
+
+// insert(...)
+
+// UNSUPPORTED: c++98, c++03
+
+#include <unordered_map>
+#include <iostream>
+#include <cassert>
+
+#include "test_macros.h"
+#include "count_new.hpp"
+#include "container_test_types.h"
+
+#if TEST_STD_VER >= 11
+template <class Arg>
+void PrintInfo(int line, Arg&& arg)
+#else
+template <class Arg>
+void PrintInfo(int line, Arg arg)
+#endif
+{
+  std::cout << "In " << __FILE__ << ":" << line << ":\n    " << arg << "\n" << std::endl;
+}
+#define PRINT(...) PrintInfo(__LINE__, __VA_ARGS__)
+
+template <class Container>
+void testContainerInsert()
+{
+  typedef typename Container::value_type ValueTp;
+  typedef Container C;
+  ConstructController* cc = getConstructController();
+  cc->reset();
+  {
+    PRINT("Testing C::insert(const value_type&)");
+    Container c;
+    const ValueTp v(42, 1);
+    cc->expect<const ValueTp&>();
+    c.insert(v);
+    assert(!cc->unchecked());
+  }
+  {
+    PRINT("Testing C::insert(value_type&)");
+    Container c;
+    ValueTp v(42, 1);
+    cc->expect<ValueTp&>();
+    c.insert(v);
+    assert(!cc->unchecked());
+  }
+  {
+    PRINT("Testing C::insert(value_type&&)");
+    Container c;
+    ValueTp v(42, 1);
+    cc->expect<ValueTp&&>();
+    c.insert(std::move(v));
+    assert(!cc->unchecked());
+  }
+  {
+    PRINT("Testing C::insert(std::initializer_list<ValueTp>)");
+    Container c;
+    std::initializer_list<ValueTp> il = { ValueTp(1, 1), ValueTp(2, 1) };
+    cc->expect<ValueTp const&>(2);
+    c.insert(il);
+    assert(!cc->unchecked());
+  }
+  {
+    PRINT("Testing C::insert(Iter, Iter) for *Iter = value_type const&");
+    Container c;
+    const ValueTp ValueList[] = { ValueTp(1, 1), ValueTp(2, 1), ValueTp(3, 1) };
+    cc->expect<ValueTp const&>(3);
+    c.insert(std::begin(ValueList), std::end(ValueList));
+    assert(!cc->unchecked());
+  }
+  {
+    PRINT("Testing C::insert(Iter, Iter) for *Iter = value_type&&");
+    Container c;
+    ValueTp ValueList[] = { ValueTp(1, 1), ValueTp(2, 1) , ValueTp(3, 1) };
+    cc->expect<ValueTp&&>(3);
+    c.insert(std::move_iterator<ValueTp*>(std::begin(ValueList)),
+             std::move_iterator<ValueTp*>(std::end(ValueList)));
+    assert(!cc->unchecked());
+  }
+  {
+    PRINT("Testing C::insert(Iter, Iter) for *Iter = value_type&");
+    Container c;
+    ValueTp ValueList[] = { ValueTp(1, 1), ValueTp(2, 1) , ValueTp(3, 1) };
+    cc->expect<ValueTp&>(3);
+    c.insert(std::begin(ValueList), std::end(ValueList));
+    assert(!cc->unchecked());
+  }
+}
+
+
+int main()
+{
+  testContainerInsert<TCT::unordered_multimap<> >();
+}

Added: libcxx/trunk/test/std/containers/unord/unord.multiset/insert_allocator_requirements.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/unord/unord.multiset/insert_allocator_requirements.pass.cpp?rev=260513&view=auto
==============================================================================
--- libcxx/trunk/test/std/containers/unord/unord.multiset/insert_allocator_requirements.pass.cpp (added)
+++ libcxx/trunk/test/std/containers/unord/unord.multiset/insert_allocator_requirements.pass.cpp Thu Feb 11 05:59:44 2016
@@ -0,0 +1,107 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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.
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_set>
+
+// class unordered_multiset
+
+// insert(...)
+
+// UNSUPPORTED: c++98, c++03
+
+#include <unordered_set>
+#include <iostream>
+#include <cassert>
+
+#include "test_macros.h"
+#include "count_new.hpp"
+#include "container_test_types.h"
+
+#if TEST_STD_VER >= 11
+template <class Arg>
+void PrintInfo(int line, Arg&& arg)
+#else
+template <class Arg>
+void PrintInfo(int line, Arg arg)
+#endif
+{
+  std::cout << "In " << __FILE__ << ":" << line << ":\n    " << arg << "\n" << std::endl;
+}
+#define PRINT(...) PrintInfo(__LINE__, __VA_ARGS__)
+
+template <class Container>
+void testContainerInsert()
+{
+  typedef typename Container::value_type ValueTp;
+  typedef Container C;
+  ConstructController* cc = getConstructController();
+  cc->reset();
+  {
+    PRINT("Testing C::insert(const value_type&)");
+    Container c;
+    const ValueTp v(42);
+    cc->expect<const ValueTp&>();
+    c.insert(v);
+    assert(!cc->unchecked());
+  }
+  {
+    PRINT("Testing C::insert(value_type&)");
+    Container c;
+    ValueTp v(42);
+    cc->expect<const ValueTp&>();
+    c.insert(v);
+    assert(!cc->unchecked());
+  }
+  {
+    PRINT("Testing C::insert(value_type&&)");
+    Container c;
+    ValueTp v(42);
+    cc->expect<ValueTp&&>();
+    c.insert(std::move(v));
+    assert(!cc->unchecked());
+  }
+  {
+    PRINT("Testing C::insert(std::initializer_list<ValueTp>)");
+    Container c;
+    std::initializer_list<ValueTp> il = { ValueTp(1), ValueTp(2) };
+    cc->expect<ValueTp const&>(2);
+    c.insert(il);
+    assert(!cc->unchecked());
+  }
+  {
+    PRINT("Testing C::insert(Iter, Iter) for *Iter = value_type const&");
+    Container c;
+    const ValueTp ValueList[] = { ValueTp(1), ValueTp(2), ValueTp(3) };
+    cc->expect<ValueTp const&>(3);
+    c.insert(std::begin(ValueList), std::end(ValueList));
+    assert(!cc->unchecked());
+  }
+  {
+    PRINT("Testing C::insert(Iter, Iter) for *Iter = value_type&&");
+    Container c;
+    ValueTp ValueList[] = { ValueTp(1), ValueTp(2) , ValueTp(3) };
+    cc->expect<ValueTp&&>(3);
+    c.insert(std::move_iterator<ValueTp*>(std::begin(ValueList)),
+             std::move_iterator<ValueTp*>(std::end(ValueList)));
+    assert(!cc->unchecked());
+  }
+  {
+    PRINT("Testing C::insert(Iter, Iter) for *Iter = value_type&");
+    Container c;
+    ValueTp ValueList[] = { ValueTp(1), ValueTp(2) , ValueTp(3) };
+    cc->expect<ValueTp&>(3);
+    c.insert(std::begin(ValueList), std::end(ValueList));
+    assert(!cc->unchecked());
+  }
+}
+
+int main()
+{
+  testContainerInsert<TCT::unordered_multiset<> >();
+}

Added: libcxx/trunk/test/std/containers/unord/unord.set/insert_allocator_requirements.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/unord/unord.set/insert_allocator_requirements.pass.cpp?rev=260513&view=auto
==============================================================================
--- libcxx/trunk/test/std/containers/unord/unord.set/insert_allocator_requirements.pass.cpp (added)
+++ libcxx/trunk/test/std/containers/unord/unord.set/insert_allocator_requirements.pass.cpp Thu Feb 11 05:59:44 2016
@@ -0,0 +1,142 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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.
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_set>
+
+// class unordered_set
+
+// insert(...)
+
+// UNSUPPORTED: c++98, c++03
+
+#include <unordered_set>
+#include <iostream>
+#include <cassert>
+
+#include "test_macros.h"
+#include "count_new.hpp"
+#include "container_test_types.h"
+
+#if TEST_STD_VER >= 11
+template <class Arg>
+void PrintInfo(int line, Arg&& arg)
+#else
+template <class Arg>
+void PrintInfo(int line, Arg arg)
+#endif
+{
+  std::cout << "In " << __FILE__ << ":" << line << ":\n    " << arg << "\n" << std::endl;
+}
+#define PRINT(...) PrintInfo(__LINE__, __VA_ARGS__)
+
+template <class Container>
+void testContainerInsert()
+{
+  typedef typename Container::value_type ValueTp;
+  typedef Container C;
+  typedef std::pair<typename C::iterator, bool> R;
+  ConstructController* cc = getConstructController();
+  cc->reset();
+  {
+    PRINT("Testing C::insert(const value_type&)");
+    Container c;
+    const ValueTp v(42);
+    cc->expect<const ValueTp&>();
+    assert(c.insert(v).second);
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      const ValueTp v2(42);
+      assert(c.insert(v2).second == false);
+    }
+  }
+  {
+    PRINT("Testing C::insert(value_type&)");
+    Container c;
+    ValueTp v(42);
+    cc->expect<const ValueTp&>();
+    assert(c.insert(v).second);
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      ValueTp v2(42);
+      assert(c.insert(v2).second == false);
+    }
+  }
+  {
+    PRINT("Testing C::insert(value_type&&)");
+    Container c;
+    ValueTp v(42);
+    cc->expect<ValueTp&&>();
+    assert(c.insert(std::move(v)).second);
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      ValueTp v2(42);
+      assert(c.insert(std::move(v2)).second == false);
+    }
+  }
+  {
+    PRINT("Testing C::insert(std::initializer_list<ValueTp>)");
+    Container c;
+    std::initializer_list<ValueTp> il = { ValueTp(1), ValueTp(2) };
+    cc->expect<ValueTp const&>(2);
+    c.insert(il);
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      c.insert(il);
+    }
+  }
+  {
+    PRINT("Testing C::insert(Iter, Iter) for *Iter = value_type const&");
+    Container c;
+    const ValueTp ValueList[] = { ValueTp(1), ValueTp(2), ValueTp(3) };
+    cc->expect<ValueTp const&>(3);
+    c.insert(std::begin(ValueList), std::end(ValueList));
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      c.insert(std::begin(ValueList), std::end(ValueList));
+    }
+  }
+  {
+    PRINT("Testing C::insert(Iter, Iter) for *Iter = value_type&&");
+    Container c;
+    ValueTp ValueList[] = { ValueTp(1), ValueTp(2) , ValueTp(3) };
+    cc->expect<ValueTp&&>(3);
+    c.insert(std::move_iterator<ValueTp*>(std::begin(ValueList)),
+             std::move_iterator<ValueTp*>(std::end(ValueList)));
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      ValueTp ValueList2[] = { ValueTp(1), ValueTp(2) , ValueTp(3) };
+      c.insert(std::move_iterator<ValueTp*>(std::begin(ValueList2)),
+               std::move_iterator<ValueTp*>(std::end(ValueList2)));
+    }
+  }
+  {
+    PRINT("Testing C::insert(Iter, Iter) for *Iter = value_type&");
+    Container c;
+    ValueTp ValueList[] = { ValueTp(1), ValueTp(2) , ValueTp(3) };
+    cc->expect<ValueTp const&>(3);
+    c.insert(std::begin(ValueList), std::end(ValueList));
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      c.insert(std::begin(ValueList), std::end(ValueList));
+    }
+  }
+}
+
+
+int main()
+{
+  testContainerInsert<TCT::unordered_set<> >();
+}

Added: libcxx/trunk/test/support/container_test_types.h
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/support/container_test_types.h?rev=260513&view=auto
==============================================================================
--- libcxx/trunk/test/support/container_test_types.h (added)
+++ libcxx/trunk/test/support/container_test_types.h Thu Feb 11 05:59:44 2016
@@ -0,0 +1,522 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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_CONTAINER_TEST_TYPES_H
+#define SUPPORT_CONTAINER_TEST_TYPES_H
+
+// container_test_types.h - A set of types used for testing STL containers.
+// The types container within this header are used to test the requirements in
+// [container.requirements.general]. The header is made up of 3 main components:
+//
+// * test-types: 'CopyInsertable', 'MoveInsertable' and 'EmplaceConstructible' -
+//    These test types are used to test the container requirements of the same
+//    name. These test types use the global 'AllocatorConstructController' to
+//    assert that they are only constructed by the containers allocator.
+//
+// * test-allocator: 'ContainerTestAllocator' - This test allocator is used to
+//    test the portions of [container.requirements.general] that pertain to the
+//    containers allocator. The three primary jobs of the test allocator are:
+//      1. Enforce that 'a.construct(...)' and 'a.destroy(...)' are only ever
+//         instantiated for 'Container::value_type'.
+//      2. Provide a mechanism of checking calls to 'a.construct(Args...)'.
+//         Including controlling when and with what types 'a.construct(...)'
+//         may be called with.
+//      3. Support the test types internals by controlling the global
+//        'AllocatorConstructController' object.
+//
+// * 'AllocatorConstructController' - This type defines an interface for testing
+//   the construction of types using an allocator. This type is used to communicate
+//   between the test author, the containers allocator, and the types
+//   being constructed by the container.
+//   The controllers primary functions are:
+//     1. Allow calls to 'a.construct(p, args...)' to be checked by a test.
+//        The test uses 'cc->expect<Args...>()' to specify that the allocator
+//        should expect one call to 'a.construct' with the specified argument
+//        types.
+//     2. Controlling the value of 'cc->isInAllocatorConstruct()' within the
+//        'construct' method. The test-types use this value to assert that
+//         they are being constructed by the allocator.
+//
+//   'AllocatorConstructController' enforces the Singleton pattern since the
+//    test-types, test-allocator and test need to share the same controller
+//    object. A pointer to the global controller is returned by
+//   'getConstructController()'.
+//
+//----------------------------------------------------------------------------
+/*
+ * Usage: The following example checks that 'unordered_map::emplace(Args&&...)'
+ *        with 'Args = [CopyInsertable<1> const&, CopyInsertible<2>&&]'
+ *        calls 'alloc.construct(value_type*, Args&&...)' with the same types.
+ *
+ * // Typedefs for container
+ * using Key = CopyInsertible<1>;
+ * using Value = CopyInsertible<2>;
+ * using ValueTp = std::pair<const Key, Value>;
+ * using Alloc = ContainerTestAllocator<ValueTp, ValueTp>;
+ * using Map = std::unordered_map<Key, Value, std::hash<Key>, std::equal_to<Key>, Alloc>;
+ *
+ * // Get the global controller, reset it, and construct an allocator with
+ * // the controller.
+ * ConstructController* cc = getConstructController();
+ * cc->reset();
+ *
+ * // Create a Map and a Key and Value to insert. Note that the test-allocator
+ * // does not need to be given 'cc'.
+ * Map m;
+ * const Key k(1);
+ * Value v(1);
+ *
+ * // Tell the controller to expect a construction from the specified types.
+ * cc->expect<Key const&, Value&&>();
+ *
+ * // Emplace the objects into the container. 'Alloc.construct(p, UArgs...)'
+ * // will assert 'cc->check<UArgs&&>()' is true which will consume
+ * // the call to 'cc->expect<...>()'.
+ * m.emplace(k, std::move(v));
+ *
+ * // Assert that the "expect" was consumed by a matching "check" call within
+ * // Alloc.
+ * assert(!cc->unexpected());
+ *
+ */
+
+#include <functional>
+#include <unordered_map>
+#include <unordered_set>
+#include <cassert>
+
+#include "test_macros.h"
+
+namespace detail {
+// TypeID - Represent a unique identifier for a type. TypeID allows equality
+// comparisons between different types.
+struct TypeID {
+  friend bool operator==(TypeID const& LHS, TypeID const& RHS)
+  {return LHS.m_id == RHS.m_id; }
+  friend bool operator!=(TypeID const& LHS, TypeID const& RHS)
+  {return LHS.m_id != RHS.m_id; }
+private:
+  explicit TEST_CONSTEXPR TypeID(const int* xid) : m_id(xid) {}
+  const int* const m_id;
+  template <class T> friend class TypeInfo;
+};
+
+// TypeInfo - Represent information for the specified type 'T', including a
+// unique TypeID.
+template <class T>
+class TypeInfo {
+public:
+  typedef T value_type;
+  typedef TypeID ID;
+  static  ID const& GetID() { static ID id(&dummy_addr); return id; }
+
+private:
+  static const int dummy_addr;
+};
+
+template <class L, class R>
+inline bool operator==(TypeInfo<L> const&, TypeInfo<R> const&)
+{ return std::is_same<L, R>::value; }
+
+template <class L, class R>
+inline bool operator!=(TypeInfo<L> const& lhs, TypeInfo<R> const& rhs)
+{ return !(lhs == rhs); }
+
+template <class T>
+const int TypeInfo<T>::dummy_addr = 42;
+
+// makeTypeID - Return the TypeID for the specified type 'T'.
+template <class T>
+inline TEST_CONSTEXPR TypeID const& makeTypeID() { return TypeInfo<T>::GetID(); }
+
+#if TEST_STD_VER >= 11
+template <class ...Args>
+struct ArgumentListID {};
+
+// makeArgumentID - Create and return a unique identifier for a given set
+// of arguments.
+template <class ...Args>
+inline TEST_CONSTEXPR TypeID const& makeArgumentID() {
+  return makeTypeID<ArgumentListID<Args...>>();
+}
+#else
+template <class A1 = void, class A2 = void, class A3 = void>
+struct ArgumentListID {};
+
+template <class A1>
+inline TypeID const& makeArgumentID() {
+  return makeTypeID<ArgumentListID<A1> >();
+}
+
+template <class A1, class A2>
+inline TypeID const& makeArgumentID() {
+  return makeTypeID<ArgumentListID<A1, A2> >();
+}
+
+template <class A1, class A2, class A3>
+inline TypeID const& makeArgumentID() {
+  return makeTypeID<ArgumentListID<A1, A2, A3> >();
+}
+#endif
+
+} // namespace detail
+
+//===----------------------------------------------------------------------===//
+//                        AllocatorConstructController
+//===----------------------------------------------------------------------===//
+
+struct AllocatorConstructController {
+  const detail::TypeID* m_expected_args;
+  bool m_allow_constructions;
+  bool m_allow_unchecked;
+  int m_expected_count;
+
+  // Check for and consume an expected construction added by 'expect'.
+  // Return true if the construction was expected and false otherwise.
+  // This should only be called by 'Allocator.construct'.
+  bool check(detail::TypeID const& tid) {
+    if (!m_expected_args)
+      assert(m_allow_unchecked);
+    bool res = *m_expected_args == tid;
+    if (m_expected_count == -1 || --m_expected_count == -1)
+      m_expected_args = nullptr;
+    return res;
+  }
+
+  // Return true iff there is an unchecked construction expression.
+  bool unchecked() {
+    return m_expected_args != nullptr;
+  }
+
+  // Expect a call to Allocator::construct with Args that match 'tid'.
+  void expect(detail::TypeID const& tid) {
+    assert(!unchecked());
+    m_expected_args = &tid;
+  }
+
+#if TEST_STD_VER >= 11
+  template <class ...Args>
+  void expect(int times = 1) {
+    assert(!unchecked());
+    assert(times > 0);
+    m_expected_count = times - 1;
+    m_expected_args = &detail::makeArgumentID<Args...>();
+  }
+  template <class ...Args>
+  bool check() {
+    return check(detail::makeArgumentID<Args...>());
+  }
+#else
+  template <class A1>
+  void expect(int times = 1) {
+    assert(!unchecked());
+    assert(times > 0);
+    m_expected_count = times - 1;
+    m_expected_args = &detail::makeArgumentID<A1>();
+  }
+  template <class A1>
+  bool check() {
+    return check(detail::makeArgumentID<A1>());
+  }
+#endif
+
+  // Return true iff the program is currently within a call to "Allocator::construct"
+  bool isInAllocatorConstruct() const {
+    return m_allow_constructions;
+  }
+
+  void inAllocatorConstruct(bool value = true) {
+    m_allow_constructions = value;
+  }
+
+  void allowUnchecked(bool value = true) {
+    m_allow_unchecked = value;
+  }
+
+  void reset() {
+    m_allow_constructions = false;
+    m_expected_args = nullptr;
+    m_allow_unchecked = false;
+    m_expected_count = -1;
+  }
+
+private:
+  friend AllocatorConstructController* getConstructController();
+  AllocatorConstructController()  { reset(); }
+  AllocatorConstructController(AllocatorConstructController const&);
+  AllocatorConstructController& operator=(AllocatorConstructController const&);
+};
+
+typedef AllocatorConstructController ConstructController;
+
+// getConstructController - Return the global allocator construction controller.
+inline ConstructController* getConstructController() {
+  static ConstructController c;
+  return &c;
+}
+
+//===----------------------------------------------------------------------===//
+//                       ContainerTestAllocator
+//===----------------------------------------------------------------------===//
+
+// ContainerTestAllocator - A STL allocator type that only allows 'construct'
+// and 'destroy' to be called for 'AllowConstructT' types. ContainerTestAllocator
+// uses the 'AllocatorConstructionController' interface.
+template <class T, class AllowConstructT>
+class ContainerTestAllocator
+{
+  struct InAllocatorConstructGuard {
+    ConstructController *m_cc;
+    bool m_old;
+    InAllocatorConstructGuard(ConstructController* cc) : m_cc(cc) {
+      if (m_cc) {
+        m_old = m_cc->isInAllocatorConstruct();
+        m_cc->inAllocatorConstruct(true);
+      }
+    }
+    ~InAllocatorConstructGuard() {
+      if (m_cc) m_cc->inAllocatorConstruct(m_old);
+    }
+  private:
+    InAllocatorConstructGuard(InAllocatorConstructGuard const&);
+    InAllocatorConstructGuard& operator=(InAllocatorConstructGuard const&);
+  };
+
+public:
+    typedef T value_type;
+
+    int construct_called;
+    int destroy_called;
+    ConstructController* controller;
+
+    ContainerTestAllocator() TEST_NOEXCEPT
+        : controller(getConstructController()) {}
+
+    explicit ContainerTestAllocator(ConstructController* c)
+       : controller(c)
+    {}
+
+    template <class U>
+    ContainerTestAllocator(ContainerTestAllocator<U, AllowConstructT> other) TEST_NOEXCEPT
+      : controller(other.controller)
+    {}
+
+    T* allocate(std::size_t n)
+    {
+        return static_cast<T*>(::operator new(n*sizeof(T)));
+    }
+
+    void deallocate(T* p, std::size_t)
+    {
+        return ::operator delete(static_cast<void*>(p));
+    }
+#if TEST_STD_VER >= 11
+    template <class Up, class ...Args>
+    void construct(Up* p, Args&&... args) {
+      static_assert((std::is_same<Up, AllowConstructT>::value),
+                    "Only allowed to construct Up");
+      assert(controller->check<Args&&...>());
+      {
+        InAllocatorConstructGuard g(controller);
+        ::new ((void*)p) Up(std::forward<Args>(args)...);
+      }
+    }
+#else
+    template <class Up, class A0>
+    void construct(Up* p, A0& a0) {
+      static_assert((std::is_same<Up, AllowConstructT>::value),
+                    "Only allowed to construct Up");
+      assert(controller->check<A0&>());
+      {
+        InAllocatorConstructGuard g(controller);
+        ::new ((void*)p) Up(a0);
+      }
+    }
+    template <class Up, class A0, class A1>
+    void construct(Up* p, A0& a0, A1& a1) {
+      static_assert((std::is_same<Up, AllowConstructT>::value),
+                    "Only allowed to construct Up");
+      assert((controller->check<A0&, A1&>()));
+      {
+        InAllocatorConstructGuard g(controller);
+        ::new ((void*)p) Up(a0, a1);
+      }
+    }
+#endif
+
+    template <class Up>
+    void destroy(Up* p) {
+      static_assert((std::is_same<Up, AllowConstructT>::value),
+                    "Only allowed to destroy Up");
+      {
+        InAllocatorConstructGuard g(controller);
+        p->~Up();
+      }
+    }
+
+    friend bool operator==(ContainerTestAllocator, ContainerTestAllocator) {return true;}
+    friend bool operator!=(ContainerTestAllocator x, ContainerTestAllocator y) {return !(x == y);}
+};
+
+#if TEST_STD_VER >= 11
+namespace test_detail {
+typedef ContainerTestAllocator<int, int> A1;
+typedef std::allocator_traits<A1> A1T;
+typedef ContainerTestAllocator<float, int> A2;
+typedef std::allocator_traits<A2> A2T;
+
+static_assert(std::is_same<A1T::rebind_traits<float>, A2T>::value, "");
+static_assert(std::is_same<A2T::rebind_traits<int>, A1T>::value, "");
+} // end namespace test_detail
+#endif
+
+//===----------------------------------------------------------------------===//
+//  'CopyInsertable', 'MoveInsertable' and 'EmplaceConstructible' test types
+//===----------------------------------------------------------------------===//
+
+template <int Dummy = 0>
+struct CopyInsertable {
+  int data;
+  mutable bool copied_once;
+  bool constructed_under_allocator;
+
+  explicit CopyInsertable(int val) : data(val), copied_once(false),
+                                     constructed_under_allocator(false) {
+    if (getConstructController()->isInAllocatorConstruct()) {
+      copied_once = true;
+      constructed_under_allocator = true;
+    }
+  }
+
+  CopyInsertable(CopyInsertable const& other) : data(other.data),
+                                                copied_once(true),
+                                                constructed_under_allocator(true) {
+    assert(getConstructController()->isInAllocatorConstruct());
+    assert(other.copied_once == false);
+    other.copied_once = true;
+  }
+
+  CopyInsertable(CopyInsertable& other) : data(other.data), copied_once(true),
+                                          constructed_under_allocator(true) {
+    assert(getConstructController()->isInAllocatorConstruct());
+    assert(other.copied_once == false);
+    other.copied_once = true;
+  }
+
+#if TEST_STD_VER >= 11
+  CopyInsertable(CopyInsertable&& other) : CopyInsertable(other) {}
+
+  // Forgive pair for not downcasting this to an lvalue it its constructors.
+  CopyInsertable(CopyInsertable const && other) : CopyInsertable(other) {}
+
+
+  template <class ...Args>
+  CopyInsertable(Args&&... args) {
+    assert(false);
+  }
+#else
+  template <class Arg>
+  CopyInsertable(Arg&) {
+    assert(false);
+  }
+#endif
+
+  ~CopyInsertable() {
+    assert(constructed_under_allocator == getConstructController()->isInAllocatorConstruct());
+  }
+
+  void reset(int value) {
+    data = value;
+    copied_once = false;
+    constructed_under_allocator = false;
+  }
+};
+
+template <int ID>
+bool operator==(CopyInsertable<ID> const& L, CopyInsertable<ID> const& R) {
+  return L.data == R.data;
+}
+
+
+template <int ID>
+bool operator!=(CopyInsertable<ID> const& L, CopyInsertable<ID> const& R) {
+  return L.data != R.data;
+}
+
+template <int ID>
+bool operator <(CopyInsertable<ID> const& L, CopyInsertable<ID> const& R) {
+  return L.data < R.data;
+}
+
+namespace std {
+template <int ID>
+struct hash< ::CopyInsertable<ID> > {
+  typedef ::CopyInsertable<ID> argument_type;
+  typedef size_t result_type;
+
+  size_t operator()(argument_type const& arg) const {
+    return arg.data;
+  }
+};
+} // namespace std
+
+// TCT - Test container type
+namespace TCT {
+
+template <class Key = CopyInsertable<1>, class Value = CopyInsertable<2> >
+struct unordered_map_type {
+    typedef std::pair<const Key, Value> ValueTp;
+    typedef
+      std::unordered_map<Key, Value, std::hash<Key>, std::equal_to<Key>,
+                              ContainerTestAllocator<ValueTp, ValueTp> >
+      type;
+};
+
+template <class Key = CopyInsertable<1>, class Value = CopyInsertable<2>>
+struct unordered_multimap_type {
+    typedef std::pair<const Key, Value> ValueTp;
+    typedef
+      std::unordered_multimap<Key, Value, std::hash<Key>, std::equal_to<Key>,
+                                   ContainerTestAllocator<ValueTp, ValueTp> >
+      type;
+};
+
+template <class Value = CopyInsertable<1> >
+struct unordered_set_type {
+  typedef
+    std::unordered_set<Value, std::hash<Value>, std::equal_to<Value>,
+                               ContainerTestAllocator<Value, Value> >
+    type;
+};
+
+template <class Value = CopyInsertable<1> >
+struct unordered_multiset_type {
+  typedef
+    std::unordered_multiset<Value, std::hash<Value>, std::equal_to<Value>,
+                                    ContainerTestAllocator<Value, Value> >
+    type;
+};
+
+#if TEST_STD_VER >= 11
+template <class ...Args>
+using unordered_map = typename unordered_map_type<Args...>::type;
+
+template <class ...Args>
+using unordered_multimap = typename unordered_multimap_type<Args...>::type;
+
+template <class ...Args>
+using unordered_set = typename unordered_set_type<Args...>::type;
+
+template <class ...Args>
+using unordered_multiset = typename unordered_multiset_type<Args...>::type;
+#endif
+
+} // end namespace TCT
+
+
+#endif // SUPPORT_CONTAINER_TEST_TYPES_H




More information about the cfe-commits mailing list