dexonsmith updated this revision to Diff 47936. dexonsmith added a comment.
Updated the patch to apply against r260513. The logic is much simpler now; thanks Eric for the cleanup. Let me know if there's anything else to do! http://reviews.llvm.org/D16360 Files: include/__hash_table test/libcxx/containers/unord/unord.map/insert_dup_alloc.pass.cpp
Index: test/libcxx/containers/unord/unord.map/insert_dup_alloc.pass.cpp =================================================================== --- /dev/null +++ test/libcxx/containers/unord/unord.map/insert_dup_alloc.pass.cpp @@ -0,0 +1,88 @@ +//===----------------------------------------------------------------------===// +// +// 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_map. + +#include <cassert> +#include <unordered_map> +#include "count_new.hpp" +#include "MoveOnly.h" + +int main() { + { + std::unordered_map<int, int> s; + assert(globalMemCounter.checkNewCalledEq(0)); + + for (int i = 0; i < 100; ++i) { + std::pair<const int, int> P(3, i); + s.insert(P); + s.insert(std::make_pair(3, i)); + s.insert(std::make_pair(3, unsigned(i))); + s.insert(s.end(), std::make_pair(3, i)); +#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES + s.emplace(std::make_pair(3, i)); + s.emplace_hint(s.end(), std::make_pair(3, i)); +#endif + { + const std::pair<int, int> P(3, i); + s.insert(P); +#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES + s.emplace(P); + s.emplace_hint(s.end(), P); +#endif + } + } + + assert(s.size() == 1); + assert(s.count(3) == 1); + assert(s.at(3) == 0); + assert(globalMemCounter.checkNewCalledEq(2)); + } + assert(globalMemCounter.checkOutstandingNewEq(0)); + globalMemCounter.reset(); +#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES + { + std::unordered_map<MoveOnly, MoveOnly> s; + assert(globalMemCounter.checkNewCalledEq(0)); + + for (int i = 0; i < 100; i++) { + s.insert(std::make_pair(MoveOnly(3), MoveOnly(i))); + s.insert(s.end(), std::make_pair(MoveOnly(3), MoveOnly(i))); + s.emplace(std::make_pair(MoveOnly(3), MoveOnly(i))); + s.emplace_hint(s.end(), std::make_pair(MoveOnly(3), MoveOnly(i))); + } + + assert(s.size() == 1); + assert(s.count(MoveOnly(3)) == 1); + assert(s.at(MoveOnly(3)) == 0); + assert(globalMemCounter.checkNewCalledEq(2)); + } + assert(globalMemCounter.checkOutstandingNewEq(0)); + globalMemCounter.reset(); + { + std::unordered_map<int, MoveOnly> s; + assert(globalMemCounter.checkNewCalledEq(0)); + + for (int i = 0; i < 100; i++) { + s.insert(std::make_pair(3, MoveOnly(i))); + s.insert(s.end(), std::make_pair(3, MoveOnly(i))); + s.emplace(std::make_pair(3, MoveOnly(i))); + s.emplace_hint(s.end(), std::make_pair(3, MoveOnly(i))); + } + + assert(s.size() == 1); + assert(s.count(3) == 1); + assert(s.at(3) == 0); + assert(globalMemCounter.checkNewCalledEq(2)); + } + assert(globalMemCounter.checkOutstandingNewEq(0)); + globalMemCounter.reset(); +#endif +} Index: include/__hash_table =================================================================== --- include/__hash_table +++ include/__hash_table @@ -100,6 +100,14 @@ return size_t(1) << (std::numeric_limits<size_t>::digits - __clz(__n-1)); } +template <class _Pair, class _Key, + class _RawPair = typename __uncvref<_Pair>::type> +struct __is_pair_with_key : false_type {}; + +template <class _Pair, class _Key, class _First, class _Second> +struct __is_pair_with_key<_Pair, _Key, pair<_First, _Second>> + : is_same<typename remove_const<_First>::type, _Key> {}; + template <class _Tp, class _Hash, class _Equal, class _Alloc> class __hash_table; template <class _NodePtr> class _LIBCPP_TYPE_VIS_ONLY __hash_iterator; @@ -901,6 +909,7 @@ 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; @@ -1039,13 +1048,41 @@ #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), + __is_pair_with_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, false_type) { + return __emplace_unique_impl(_VSTD::forward<_Pp>(__x)); + } + template <class _Pp> + _LIBCPP_INLINE_VISIBILITY + pair<iterator, bool> __emplace_unique_extract_key(_Pp&& __x, true_type) { + 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); @@ -1987,7 +2024,7 @@ 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());
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits