dexonsmith updated this revision to Diff 50514. dexonsmith added a comment.
A few updates: - Rebased on top of http://reviews.llvm.org/D18115. - Rewrote the test to match suggested style. - Updated the code to catch unordered_set::emplace as well, using a __can_extract_key trait and a companion __extract_key functor. Sorry for the latency reposting; let me know how this looks. http://reviews.llvm.org/D16360 Files: include/__hash_table test/libcxx/containers/unord/unord.map/insert_dup_alloc.pass.cpp test/libcxx/containers/unord/unord.set/insert_dup_alloc.pass.cpp
Index: test/libcxx/containers/unord/unord.set/insert_dup_alloc.pass.cpp =================================================================== --- test/libcxx/containers/unord/unord.set/insert_dup_alloc.pass.cpp +++ test/libcxx/containers/unord/unord.set/insert_dup_alloc.pass.cpp @@ -60,6 +60,21 @@ const ValueTp v(3); assert(!c.insert(v).second); } + + PRINT("Checking for mallocs in emplace(value_type&&)"); + assert(!c.emplace(ValueTp(3)).second); + + PRINT("Checking for mallocs in emplace(value_type&)"); + { + ValueTp v(3); + assert(!c.emplace(v).second); + } + + PRINT("Checking for mallocs in emplace(const value_type&)"); + { + const ValueTp v(3); + assert(!c.emplace(v).second); + } } int main() 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,103 @@ +//===----------------------------------------------------------------------===// +// +// 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 <iostream> +#include <unordered_map> + +#include "container_test_types.h" +#include "count_new.hpp" +#include "test_macros.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 std::pair<typename ValueTp::first_type, typename ValueTp::second_type> + PairTp; + typedef Container C; + typedef std::pair<typename C::iterator, bool> R; + ConstructController* cc = getConstructController(); + cc->reset(); + Container c; + cc->expect<ValueTp&&>(); + + PRINT("Expect a malloc in initial insertion"); + assert(c.insert(ValueTp(3, 4)).second); + assert(!cc->unchecked()); + DisableAllocationGuard g; + + PRINT("Checking for mallocs in insert(value_type&&)"); + assert(!c.insert(ValueTp(3, 4)).second); + assert(!c.insert(PairTp(3, 4)).second); + + PRINT("Checking for mallocs in insert(value_type&)"); + { + ValueTp v(3, 4); + assert(!c.insert(v).second); + } + { + PairTp v(3, 4); + assert(!c.insert(v).second); + } + + PRINT("Checking for mallocs in insert(const value_type&)"); + { + const ValueTp v(3, 4); + assert(!c.insert(v).second); + } + { + const PairTp v(3, 4); + assert(!c.insert(v).second); + } + + PRINT("Checking for mallocs in emplace(value_type&&)"); + assert(!c.emplace(ValueTp(3, 4)).second); + assert(!c.emplace(PairTp(3, 4)).second); + + PRINT("Checking for mallocs in emplace(value_type&)"); + { + ValueTp v(3, 4); + assert(!c.emplace(v).second); + } + { + PairTp v(3, 4); + assert(!c.emplace(v).second); + } + + PRINT("Checking for mallocs in emplace(const value_type&)"); + { + const ValueTp v(3, 4); + assert(!c.emplace(v).second); + } + { + const PairTp v(3, 4); + assert(!c.emplace(v).second); + } +} + +int main() +{ + testContainerInsert<TCT::unordered_map<> >(); +} Index: include/__hash_table =================================================================== --- include/__hash_table +++ include/__hash_table @@ -100,6 +100,34 @@ return size_t(1) << (std::numeric_limits<size_t>::digits - __clz(__n-1)); } +template <class _ValTy, class _Key> +struct __extract_key; + +template <class _ValTy, class _Key, + class _RawValTy = typename __uncvref<_ValTy>::type> +struct __can_extract_key + : is_same< + typename remove_const<typename remove_reference<_ValTy>::type>::type, + _Key> {}; +template <class _Key> +struct __extract_key<_Key, _Key> { + const _Key &operator()(const _Key &__key) { return __key; } +}; + +template <class _Pair, class _Key, class _First, class _Second> +struct __can_extract_key<_Pair, _Key, pair<_First, _Second>> + : is_same<typename remove_const<_First>::type, _Key> {}; +template <class _Key, class _Second> +struct __extract_key<pair<_Key, _Second>, _Key> { + const _Key &operator()(const pair<_Key, _Second> &__p) { return __p.first; } +}; +template <class _Key, class _Second> +struct __extract_key<pair<const _Key, _Second>, _Key> { + const _Key &operator()(const pair<const _Key, _Second> &__p) { + return __p.first; + } +}; + template <class _Tp, class _Hash, class _Equal, class _Alloc> class __hash_table; template <class _NodePtr> class _LIBCPP_TYPE_VIS_ONLY __hash_iterator; @@ -903,6 +931,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; @@ -1041,13 +1070,43 @@ #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, 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( + __extract_key<typename __uncvref<_Pp>::type, key_type>()(__x), + _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 +2048,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