[libcxx] r263746 - unord: Extract key to avoid preemptive mallocs in insert/emplace

Duncan P. N. Exon Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 17 13:45:20 PDT 2016


Author: dexonsmith
Date: Thu Mar 17 15:45:20 2016
New Revision: 263746

URL: http://llvm.org/viewvc/llvm-project?rev=263746&view=rev
Log:
unord: Extract key to avoid preemptive mallocs in insert/emplace

unordered_set::emplace and unordered_map::emplace construct a node, then
try to insert it.  If insertion fails, the node gets deleted.

To avoid this unnecessary malloc traffic, check to see if the argument
to emplace has the appropriate key_type.  If so, we can use that key
directly and delay the malloc until we're sure we're inserting something
new.

Test updates by Eric Fiselier, who rewrote the old allocation tests to
include the new cases.

There are two orthogonal future directions:

1. Apply the same optimization to set and map.

2. Extend the optimization to when the argument is not key_type, but can
   be converted to it without side effects.  Ideally, we could do this
   whenever key_type is trivially destructible and the argument is
   trivially convertible to key_type, but in practise the relevant type
   traits "blow up sometimes".  At least, we should catch a few simple
   cases (such as when both are primitive types).

Added:
    libcxx/trunk/test/std/containers/unord/unord.map/unord.map.modifiers/insert_and_emplace_allocator_requirements.pass.cpp
      - copied, changed from r263688, libcxx/trunk/test/std/containers/unord/unord.map/unord.map.modifiers/insert_allocator_requirements.pass.cpp
    libcxx/trunk/test/std/containers/unord/unord.set/insert_and_emplace_allocator_requirements.pass.cpp
      - copied, changed from r263688, libcxx/trunk/test/std/containers/unord/unord.set/insert_allocator_requirements.pass.cpp
Removed:
    libcxx/trunk/test/libcxx/containers/unord/unord.set/insert_dup_alloc.pass.cpp
    libcxx/trunk/test/std/containers/unord/unord.map/unord.map.modifiers/insert_allocator_requirements.pass.cpp
    libcxx/trunk/test/std/containers/unord/unord.set/insert_allocator_requirements.pass.cpp
Modified:
    libcxx/trunk/include/__hash_table

Modified: libcxx/trunk/include/__hash_table
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__hash_table?rev=263746&r1=263745&r2=263746&view=diff
==============================================================================
--- libcxx/trunk/include/__hash_table (original)
+++ libcxx/trunk/include/__hash_table Thu Mar 17 15:45:20 2016
@@ -100,6 +100,23 @@ __next_hash_pow2(size_t __n)
     return size_t(1) << (std::numeric_limits<size_t>::digits - __clz(__n-1));
 }
 
+#ifndef _LIBCPP_CXX03_LANG
+struct __extract_key_fail_tag {};
+struct __extract_key_self_tag {};
+struct __extract_key_first_tag {};
+
+template <class _ValTy, class _Key,
+          class _RawValTy = typename __unconstref<_ValTy>::type>
+struct __can_extract_key
+    : conditional<is_same<_RawValTy, _Key>::value, __extract_key_self_tag,
+                  __extract_key_fail_tag>::type {};
+
+template <class _Pair, class _Key, class _First, class _Second>
+struct __can_extract_key<_Pair, _Key, pair<_First, _Second>>
+    : conditional<is_same<typename remove_const<_First>::type, _Key>::value,
+                  __extract_key_first_tag, __extract_key_fail_tag>::type {};
+#endif
+
 template <class _Tp, class _Hash, class _Equal, class _Alloc> class __hash_table;
 
 template <class _NodePtr>      class _LIBCPP_TYPE_VIS_ONLY __hash_iterator;
@@ -903,6 +920,7 @@ public:
 
     typedef typename _NodeTypes::__node_value_type           __node_value_type;
     typedef typename _NodeTypes::__container_value_type      __container_value_type;
+    typedef typename _NodeTypes::key_type                    key_type;
     typedef value_type&                              reference;
     typedef const value_type&                        const_reference;
     typedef typename __alloc_traits::pointer         pointer;
@@ -1041,13 +1059,49 @@ public:
 
 #ifndef _LIBCPP_CXX03_LANG
     template <class _Key, class ..._Args>
+    _LIBCPP_INLINE_VISIBILITY
     pair<iterator, bool> __emplace_unique_key_args(_Key const& __k, _Args&&... __args);
 
     template <class... _Args>
-    pair<iterator, bool> __emplace_unique(_Args&&... __args);
+    _LIBCPP_INLINE_VISIBILITY
+    pair<iterator, bool> __emplace_unique_impl(_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... _Args>
+    _LIBCPP_INLINE_VISIBILITY
     iterator __emplace_multi(_Args&&... __args);
     template <class... _Args>
+    _LIBCPP_INLINE_VISIBILITY
     iterator __emplace_hint_multi(const_iterator __p, _Args&&... __args);
 
 
@@ -1989,7 +2043,7 @@ __done:
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 template <class... _Args>
 pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator, bool>
-__hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_unique(_Args&&... __args)
+__hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_unique_impl(_Args&&... __args)
 {
     __node_holder __h = __construct_node(_VSTD::forward<_Args>(__args)...);
     pair<iterator, bool> __r = __node_insert_unique(__h.get());

Removed: libcxx/trunk/test/libcxx/containers/unord/unord.set/insert_dup_alloc.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/containers/unord/unord.set/insert_dup_alloc.pass.cpp?rev=263745&view=auto
==============================================================================
--- libcxx/trunk/test/libcxx/containers/unord/unord.set/insert_dup_alloc.pass.cpp (original)
+++ libcxx/trunk/test/libcxx/containers/unord/unord.set/insert_dup_alloc.pass.cpp (removed)
@@ -1,48 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-//                     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.
-//
-//===----------------------------------------------------------------------===//
-
-// Check that we don't allocate when trying to insert a duplicate value into a
-// unordered_set. See PR12999 http://llvm.org/bugs/show_bug.cgi?id=12999
-
-#include <cassert>
-#include <unordered_set>
-#include "count_new.hpp"
-#include "MoveOnly.h"
-
-int main()
-{
-    {
-    std::unordered_set<int> s;
-    assert(globalMemCounter.checkNewCalledEq(0));
-
-    for(int i=0; i < 100; ++i)
-        s.insert(3);
-
-    assert(s.size() == 1);
-    assert(s.count(3) == 1);
-    assert(globalMemCounter.checkNewCalledEq(2));
-    }
-    assert(globalMemCounter.checkOutstandingNewEq(0));
-    globalMemCounter.reset();
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
-    {
-    std::unordered_set<MoveOnly> s;
-    assert(globalMemCounter.checkNewCalledEq(0));
-
-    for(int i=0; i<100; i++)
-        s.insert(MoveOnly(3));
-
-    assert(s.size() == 1);
-    assert(s.count(MoveOnly(3)) == 1);
-    assert(globalMemCounter.checkNewCalledEq(2));
-    }
-    assert(globalMemCounter.checkOutstandingNewEq(0));
-    globalMemCounter.reset();
-#endif
-}

Removed: 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=263745&view=auto
==============================================================================
--- libcxx/trunk/test/std/containers/unord/unord.map/unord.map.modifiers/insert_allocator_requirements.pass.cpp (original)
+++ libcxx/trunk/test/std/containers/unord/unord.map/unord.map.modifiers/insert_allocator_requirements.pass.cpp (removed)
@@ -1,143 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-//                     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<> >();
-}

Copied: libcxx/trunk/test/std/containers/unord/unord.map/unord.map.modifiers/insert_and_emplace_allocator_requirements.pass.cpp (from r263688, 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_and_emplace_allocator_requirements.pass.cpp?p2=libcxx/trunk/test/std/containers/unord/unord.map/unord.map.modifiers/insert_and_emplace_allocator_requirements.pass.cpp&p1=libcxx/trunk/test/std/containers/unord/unord.map/unord.map.modifiers/insert_allocator_requirements.pass.cpp&r1=263688&r2=263746&rev=263746&view=diff
==============================================================================
--- libcxx/trunk/test/std/containers/unord/unord.map/unord.map.modifiers/insert_allocator_requirements.pass.cpp (original)
+++ libcxx/trunk/test/std/containers/unord/unord.map/unord.map.modifiers/insert_and_emplace_allocator_requirements.pass.cpp Thu Mar 17 15:45:20 2016
@@ -84,6 +84,19 @@ void testContainerInsert()
     }
   }
   {
+    PRINT("Testing C::insert(const value_type&&)");
+    Container c;
+    const ValueTp v(42, 1);
+    cc->expect<const ValueTp&>();
+    assert(c.insert(std::move(v)).second);
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      const 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) };
@@ -137,7 +150,100 @@ void testContainerInsert()
 }
 
 
+template <class Container>
+void testContainerEmplace()
+{
+  typedef typename Container::value_type ValueTp;
+  typedef typename Container::key_type Key;
+  typedef typename Container::mapped_type Mapped;
+  typedef typename std::pair<Key, Mapped> NonConstKeyPair;
+  typedef Container C;
+  typedef std::pair<typename C::iterator, bool> R;
+  ConstructController* cc = getConstructController();
+  cc->reset();
+  {
+    PRINT("Testing C::emplace(const value_type&)");
+    Container c;
+    const ValueTp v(42, 1);
+    cc->expect<const ValueTp&>();
+    assert(c.emplace(v).second);
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      const ValueTp v2(42, 1);
+      assert(c.emplace(v2).second == false);
+    }
+  }
+  {
+    PRINT("Testing C::emplace(value_type&)");
+    Container c;
+    ValueTp v(42, 1);
+    cc->expect<ValueTp&>();
+    assert(c.emplace(v).second);
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      ValueTp v2(42, 1);
+      assert(c.emplace(v2).second == false);
+    }
+  }
+  {
+    PRINT("Testing C::emplace(value_type&&)");
+    Container c;
+    ValueTp v(42, 1);
+    cc->expect<ValueTp&&>();
+    assert(c.emplace(std::move(v)).second);
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      ValueTp v2(42, 1);
+      assert(c.emplace(std::move(v2)).second == false);
+    }
+  }
+  {
+    PRINT("Testing C::emplace(const value_type&&)");
+    Container c;
+    const ValueTp v(42, 1);
+    cc->expect<const ValueTp&&>();
+    assert(c.emplace(std::move(v)).second);
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      const ValueTp v2(42, 1);
+      assert(c.emplace(std::move(v2)).second == false);
+    }
+  }
+  {
+    PRINT("Testing C::emplace(pair<Key, Mapped> const&)");
+    Container c;
+    const NonConstKeyPair v(42, 1);
+    cc->expect<const NonConstKeyPair&>();
+    assert(c.emplace(v).second);
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      const NonConstKeyPair v2(42, 1);
+      assert(c.emplace(v2).second == false);
+    }
+  }
+  {
+    PRINT("Testing C::emplace(pair<Key, Mapped> &&)");
+    Container c;
+    NonConstKeyPair v(42, 1);
+    cc->expect<NonConstKeyPair&&>();
+    assert(c.emplace(std::move(v)).second);
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      NonConstKeyPair v2(42, 1);
+      assert(c.emplace(std::move(v2)).second == false);
+    }
+  }
+}
+
+
 int main()
 {
   testContainerInsert<TCT::unordered_map<> >();
+  testContainerEmplace<TCT::unordered_map<> >();
 }

Removed: 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=263745&view=auto
==============================================================================
--- libcxx/trunk/test/std/containers/unord/unord.set/insert_allocator_requirements.pass.cpp (original)
+++ libcxx/trunk/test/std/containers/unord/unord.set/insert_allocator_requirements.pass.cpp (removed)
@@ -1,142 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-//                     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<> >();
-}

Copied: libcxx/trunk/test/std/containers/unord/unord.set/insert_and_emplace_allocator_requirements.pass.cpp (from r263688, 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_and_emplace_allocator_requirements.pass.cpp?p2=libcxx/trunk/test/std/containers/unord/unord.set/insert_and_emplace_allocator_requirements.pass.cpp&p1=libcxx/trunk/test/std/containers/unord/unord.set/insert_allocator_requirements.pass.cpp&r1=263688&r2=263746&rev=263746&view=diff
==============================================================================
--- libcxx/trunk/test/std/containers/unord/unord.set/insert_allocator_requirements.pass.cpp (original)
+++ libcxx/trunk/test/std/containers/unord/unord.set/insert_and_emplace_allocator_requirements.pass.cpp Thu Mar 17 15:45:20 2016
@@ -12,6 +12,7 @@
 // class unordered_set
 
 // insert(...)
+// emplace(...)
 
 // UNSUPPORTED: c++98, c++03
 
@@ -83,6 +84,19 @@ void testContainerInsert()
     }
   }
   {
+    PRINT("Testing C::insert(const value_type&&)");
+    Container c;
+    const ValueTp v(42);
+    cc->expect<const ValueTp&>();
+    assert(c.insert(std::move(v)).second);
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      const 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) };
@@ -136,7 +150,71 @@ void testContainerInsert()
 }
 
 
+template <class Container>
+void testContainerEmplace()
+{
+  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::emplace(const value_type&)");
+    Container c;
+    const ValueTp v(42);
+    cc->expect<const ValueTp&>();
+    assert(c.emplace(v).second);
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      const ValueTp v2(42);
+      assert(c.emplace(v2).second == false);
+    }
+  }
+  {
+    PRINT("Testing C::emplace(value_type&)");
+    Container c;
+    ValueTp v(42);
+    cc->expect<ValueTp&>();
+    assert(c.emplace(v).second);
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      ValueTp v2(42);
+      assert(c.emplace(v2).second == false);
+    }
+  }
+  {
+    PRINT("Testing C::emplace(value_type&&)");
+    Container c;
+    ValueTp v(42);
+    cc->expect<ValueTp&&>();
+    assert(c.emplace(std::move(v)).second);
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      ValueTp v2(42);
+      assert(c.emplace(std::move(v2)).second == false);
+    }
+  }
+  {
+    PRINT("Testing C::emplace(const value_type&&)");
+    Container c;
+    const ValueTp v(42);
+    cc->expect<const ValueTp&&>();
+    assert(c.emplace(std::move(v)).second);
+    assert(!cc->unchecked());
+    {
+      DisableAllocationGuard g;
+      const ValueTp v2(42);
+      assert(c.emplace(std::move(v2)).second == false);
+    }
+  }
+}
+
+
 int main()
 {
   testContainerInsert<TCT::unordered_set<> >();
+  testContainerEmplace<TCT::unordered_set<> >();
 }




More information about the cfe-commits mailing list