Extract key to avoid preemptive mallocs in insert/emplace in associative containers

Summary: This patch applies Duncan's work on __hash_table to __tree.

Reviewers: mclow.lists, dexonsmith

Subscribers: dexonsmith, cfe-commits

Differential Revision: http://reviews.llvm.org/D18637

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@266491 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/__tree b/include/__tree
index 314d5eb..eb6ff05 100644
--- a/include/__tree
+++ b/include/__tree
@@ -1064,16 +1064,85 @@
     __emplace_hint_unique_key_args(const_iterator, _Key const&, _Args&&...);
 
     template <class... _Args>
-    pair<iterator, bool> __emplace_unique(_Args&&... __args);
+    pair<iterator, bool> __emplace_unique_impl(_Args&&... __args);
 
     template <class... _Args>
-    iterator __emplace_hint_unique(const_iterator __p, _Args&&... __args);
+    iterator __emplace_hint_unique_impl(const_iterator __p, _Args&&... __args);
 
     template <class... _Args>
     iterator __emplace_multi(_Args&&... __args);
 
     template <class... _Args>
     iterator __emplace_hint_multi(const_iterator __p, _Args&&... __args);
+
+    template <class _Pp>
+    _LIBCPP_INLINE_VISIBILITY
+    pair<iterator, bool> __emplace_unique(_Pp&& __x) {
+        return __emplace_unique_extract_key(_VSTD::forward<_Pp>(__x),
+                                            __can_extract_key<_Pp, key_type>());
+    }
+
+    template <class... _Args>
+    _LIBCPP_INLINE_VISIBILITY
+    pair<iterator, bool> __emplace_unique(_Args&&... __args) {
+        return __emplace_unique_impl(_VSTD::forward<_Args>(__args)...);
+    }
+
+    template <class _Pp>
+    _LIBCPP_INLINE_VISIBILITY
+    pair<iterator, bool>
+    __emplace_unique_extract_key(_Pp&& __x, __extract_key_fail_tag) {
+      return __emplace_unique_impl(_VSTD::forward<_Pp>(__x));
+    }
+
+    template <class _Pp>
+    _LIBCPP_INLINE_VISIBILITY
+    pair<iterator, bool>
+    __emplace_unique_extract_key(_Pp&& __x, __extract_key_self_tag) {
+      return __emplace_unique_key_args(__x, _VSTD::forward<_Pp>(__x));
+    }
+
+    template <class _Pp>
+    _LIBCPP_INLINE_VISIBILITY
+    pair<iterator, bool>
+    __emplace_unique_extract_key(_Pp&& __x, __extract_key_first_tag) {
+      return __emplace_unique_key_args(__x.first, _VSTD::forward<_Pp>(__x));
+    }
+
+    template <class _Pp>
+    _LIBCPP_INLINE_VISIBILITY
+    iterator __emplace_hint_unique(const_iterator __p, _Pp&& __x) {
+        return __emplace_hint_unique_extract_key(__p, _VSTD::forward<_Pp>(__x),
+                                            __can_extract_key<_Pp, key_type>());
+    }
+
+    template <class... _Args>
+    _LIBCPP_INLINE_VISIBILITY
+    iterator __emplace_hint_unique(const_iterator __p, _Args&&... __args) {
+        return __emplace_hint_unique_impl(__p, _VSTD::forward<_Args>(__args)...);
+    }
+
+    template <class _Pp>
+    _LIBCPP_INLINE_VISIBILITY
+    iterator
+    __emplace_hint_unique_extract_key(const_iterator __p, _Pp&& __x, __extract_key_fail_tag) {
+      return __emplace_hint_unique_impl(__p, _VSTD::forward<_Pp>(__x));
+    }
+
+    template <class _Pp>
+    _LIBCPP_INLINE_VISIBILITY
+    iterator
+    __emplace_hint_unique_extract_key(const_iterator __p, _Pp&& __x, __extract_key_self_tag) {
+      return __emplace_hint_unique_key_args(__p, __x, _VSTD::forward<_Pp>(__x));
+    }
+
+    template <class _Pp>
+    _LIBCPP_INLINE_VISIBILITY
+    iterator
+    __emplace_hint_unique_extract_key(const_iterator __p, _Pp&& __x, __extract_key_first_tag) {
+      return __emplace_hint_unique_key_args(__p, __x.first, _VSTD::forward<_Pp>(__x));
+    }
+
 #else
     template <class _Key, class _Args>
     _LIBCPP_INLINE_VISIBILITY
@@ -1989,7 +2058,7 @@
 template <class _Tp, class _Compare, class _Allocator>
 template <class... _Args>
 pair<typename __tree<_Tp, _Compare, _Allocator>::iterator, bool>
-__tree<_Tp, _Compare, _Allocator>::__emplace_unique(_Args&&... __args)
+__tree<_Tp, _Compare, _Allocator>::__emplace_unique_impl(_Args&&... __args)
 {
     __node_holder __h = __construct_node(_VSTD::forward<_Args>(__args)...);
     __node_base_pointer __parent;
@@ -2008,7 +2077,7 @@
 template <class _Tp, class _Compare, class _Allocator>
 template <class... _Args>
 typename __tree<_Tp, _Compare, _Allocator>::iterator
-__tree<_Tp, _Compare, _Allocator>::__emplace_hint_unique(const_iterator __p, _Args&&... __args)
+__tree<_Tp, _Compare, _Allocator>::__emplace_hint_unique_impl(const_iterator __p, _Args&&... __args)
 {
     __node_holder __h = __construct_node(_VSTD::forward<_Args>(__args)...);
     __node_base_pointer __parent;