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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits