Index: include/memory =================================================================== --- include/memory +++ include/memory @@ -1318,49 +1318,134 @@ #endif // _LIBCPP_HAS_NO_ADVANCED_SFINAE -#if !defined(_LIBCPP_HAS_NO_ADVANCED_SFINAE) && !defined(_LIBCPP_HAS_NO_VARIADICS) +#if !defined(_LIBCPP_CXX03_LANG) + +namespace __alloc_helpers { + + +template +auto __has_allocator_destroy_test(_Alloc& __a, _Pointer&& __p) + -> decltype(__a.destroy(__p), true_type()); + +false_type __has_allocator_destroy_test(...); + +template +struct __has_allocator_destroy : decltype(__alloc_helpers::__has_allocator_destroy_test( + _VSTD::declval<_Alloc&>(), + _VSTD::declval<_Tp*>())) +{ +}; + +template +using __alloc_destroy_tag = typename + conditional< + __has_allocator_destroy<_Alloc, _Tp>::value, + integral_constant, + __lazy_conditional< + is_destructible<_Tp>, + integral_constant, + integral_constant + > + >::type::type; + + +template +inline _LIBCPP_INLINE_VISIBILITY +void __alloc_destroy_imp(integral_constant, _Alloc& __a, _Tp* __p) { + __a.destroy(__p); +} + +template +inline _LIBCPP_INLINE_VISIBILITY +void __alloc_destroy_imp(integral_constant, _Alloc&, _Tp* __p) { + __p->~_Tp(); +} + +template +inline _LIBCPP_INLINE_VISIBILITY +void __alloc_destroy(_Alloc& __a, _Tp* __p) { + __alloc_helpers::__alloc_destroy_imp(__alloc_destroy_tag<_Alloc, _Tp>(), __a, __p); +} template -decltype(_VSTD::declval<_Alloc>().construct(_VSTD::declval<_Tp*>(), - _VSTD::declval<_Args>()...), - true_type()) -__has_construct_test(_Alloc&& __a, _Tp* __p, _Args&& ...__args); +auto __has_allocator_construct_test(_Alloc& __a, _Tp* __p, _Args&& ...__args) + -> decltype(__a.construct(__p, _VSTD::forward<_Args>(__args)...) + , true_type()); -template -false_type -__has_construct_test(const _Alloc& __a, _Pointer&& __p, _Args&& ...__args); +false_type __has_allocator_construct_test(...); template -struct __has_construct - : integral_constant(), - declval<_Pointer>(), - declval<_Args>()...)), - true_type>::value> +struct __has_allocator_construct : decltype(__alloc_helpers::__has_allocator_construct_test( + _VSTD::declval<_Alloc&>(), + _VSTD::declval<_Pointer>(), + _VSTD::declval<_Args>()...)) { }; -template -auto -__has_destroy_test(_Alloc&& __a, _Pointer&& __p) - -> decltype(__a.destroy(__p), true_type()); +template +auto __has_placement_new_test(_Tp* __p, _Args&& ...__args) + -> decltype(::new((void*)__p) _Tp(_VSTD::forward<_Args>(__args)...) + , true_type()); -template -auto -__has_destroy_test(const _Alloc& __a, _Pointer&& __p) - -> false_type; +false_type __has_placement_new_test(...); -template -struct __has_destroy - : integral_constant(), - declval<_Pointer>())), - true_type>::value> +template +struct __has_placement_new : decltype(__alloc_helpers::__has_placement_new_test( + (_Tp*)nullptr, + _VSTD::declval<_Args>()...)) { }; + +template +using __alloc_construct_tag = typename + conditional< + __has_allocator_construct<_Alloc, _Tp*, _Args...>::value, + integral_constant, + __lazy_conditional< + __has_placement_new<_Tp, _Args...>, + integral_constant, + integral_constant + > + >::type::type; + + +template +inline _LIBCPP_INLINE_VISIBILITY +void __alloc_construct_imp(integral_constant, _Alloc& __a, _Tp* __p, _Args&&... __args) { + __a.construct(__p, _VSTD::forward<_Args>(__args)...); +} + +template +inline _LIBCPP_INLINE_VISIBILITY +void __alloc_construct_imp(integral_constant, _Alloc&, _Tp* __p, _Args&&... __args) { + ::new ((void*)__p) _Tp(_VSTD::forward<_Args>(__args)...); +} + +template +inline _LIBCPP_INLINE_VISIBILITY +void __alloc_construct(_Alloc& __a, _Tp* __p, _Args&&... __args) { + __alloc_helpers::__alloc_construct_imp( + __alloc_construct_tag<_Alloc, _Tp, _Args...>(), + __a, __p, _VSTD::forward<_Args>(__args)...); +} + + +} // end namespace __alloc_helpers + +using __alloc_helpers::__has_allocator_construct; + +template +using __is_alloc_destructible = integral_constant::value != 0 +>; + +template +using __is_alloc_constructible = integral_constant::value != 0 && + __alloc_helpers::__alloc_destroy_tag<_Alloc, _Tp>::value != 0 +>; + template auto __has_max_size_test(_Alloc&& __a) @@ -1399,28 +1484,17 @@ { }; -#else // _LIBCPP_HAS_NO_ADVANCED_SFINAE - -#ifndef _LIBCPP_HAS_NO_VARIADICS - -template -struct __has_construct - : false_type -{ -}; - -#else // _LIBCPP_HAS_NO_VARIADICS +#else // _LIBCPP_CXX03_LANG -template -struct __has_construct - : false_type -{ -}; +template +struct __has_allocator_construct : false_type {}; -#endif // _LIBCPP_HAS_NO_VARIADICS +template +struct __is_alloc_constructible : true_type {}; template -struct __has_destroy +struct __has_allocator_destroy : false_type { }; @@ -1437,7 +1511,7 @@ { }; -#endif // _LIBCPP_HAS_NO_ADVANCED_SFINAE +#endif // _LIBCPP_CXX03_LANG template ::value> struct __alloc_traits_difference_type @@ -1497,12 +1571,14 @@ static void deallocate(allocator_type& __a, pointer __p, size_type __n) _NOEXCEPT {__a.deallocate(__p, __n);} -#ifndef _LIBCPP_HAS_NO_VARIADICS +#ifndef _LIBCPP_CXX03_LANG template - _LIBCPP_INLINE_VISIBILITY - static void construct(allocator_type& __a, _Tp* __p, _Args&&... __args) - {__construct(__has_construct(), - __a, __p, _VSTD::forward<_Args>(__args)...);} + _LIBCPP_INLINE_VISIBILITY + static + typename enable_if<__is_alloc_constructible::value>::type + construct(allocator_type& __a, _Tp* __p, _Args&&... __args) { + __alloc_helpers::__alloc_construct(__a, __p, _VSTD::forward<_Args>(__args)...); + } #else // _LIBCPP_HAS_NO_VARIADICS template _LIBCPP_INLINE_VISIBILITY @@ -1530,12 +1606,20 @@ { ::new ((void*)__p) _Tp(__a0, __a1, __a2); } -#endif // _LIBCPP_HAS_NO_VARIADICS +#endif // _LIBCPP_CXX03_LANG +#ifndef _LIBCPP_CXX03_LANG template - _LIBCPP_INLINE_VISIBILITY - static void destroy(allocator_type& __a, _Tp* __p) - {__destroy(__has_destroy(), __a, __p);} + _LIBCPP_INLINE_VISIBILITY static + typename enable_if<__is_alloc_destructible::value>::type + destroy(allocator_type& __a, _Tp* __p) + { __alloc_helpers::__alloc_destroy(__a, __p); } +#else + template + _LIBCPP_INLINE_VISIBILITY static + static void destroy(allocator_type&, _Tp* __p) + { __p->~_Tp(); } +#endif _LIBCPP_INLINE_VISIBILITY static size_type max_size(const allocator_type& __a) _NOEXCEPT @@ -1564,7 +1648,7 @@ typename enable_if < (is_same >::value - || !__has_construct::value) && + || !__has_allocator_construct::value) && is_trivially_move_constructible<_Tp>::value, void >::type @@ -1594,7 +1678,7 @@ typename enable_if < (is_same >::value - || !__has_construct::value) && + || !__has_allocator_construct::value) && is_trivially_move_constructible<_Tp>::value, void >::type @@ -1628,7 +1712,7 @@ typename enable_if < (is_same >::value - || !__has_construct::value) && + || !__has_allocator_construct::value) && is_trivially_move_constructible<_Tp>::value, void >::type @@ -1651,18 +1735,6 @@ const_void_pointer, false_type) {return __a.allocate(__n);} -#ifndef _LIBCPP_HAS_NO_VARIADICS - template - _LIBCPP_INLINE_VISIBILITY - static void __construct(true_type, allocator_type& __a, _Tp* __p, _Args&&... __args) - {__a.construct(__p, _VSTD::forward<_Args>(__args)...);} - template - _LIBCPP_INLINE_VISIBILITY - static void __construct(false_type, allocator_type&, _Tp* __p, _Args&&... __args) - { - ::new ((void*)__p) _Tp(_VSTD::forward<_Args>(__args)...); - } -#endif // _LIBCPP_HAS_NO_VARIADICS template _LIBCPP_INLINE_VISIBILITY @@ -1740,12 +1812,11 @@ {return size_type(~0) / sizeof(_Tp);} #if !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS) template - _LIBCPP_INLINE_VISIBILITY - void - construct(_Up* __p, _Args&&... __args) - { + _LIBCPP_INLINE_VISIBILITY + typename enable_if::value>::type + construct(_Up* __p, _Args&&... __args) { ::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...); - } + } #else // !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS) _LIBCPP_INLINE_VISIBILITY void @@ -1836,12 +1907,11 @@ {return size_type(~0) / sizeof(_Tp);} #if !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS) template - _LIBCPP_INLINE_VISIBILITY - void - construct(_Up* __p, _Args&&... __args) - { + _LIBCPP_INLINE_VISIBILITY + typename enable_if::value>::type + construct(_Up* __p, _Args&&... __args) { ::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...); - } + } #else // !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS) _LIBCPP_INLINE_VISIBILITY void Index: include/type_traits =================================================================== --- include/type_traits +++ include/type_traits @@ -410,6 +410,9 @@ template struct _LIBCPP_TYPE_VIS_ONLY conditional {typedef _Then type;}; +template +struct _LIBCPP_TYPE_VIS_ONLY __lazy_conditional : conditional<_Pred::value, _If, _Then> {}; + #if _LIBCPP_STD_VER > 11 template using conditional_t = typename conditional<_Bp, _If, _Then>::type; #endif Index: include/vector =================================================================== --- include/vector +++ include/vector @@ -576,7 +576,8 @@ < __is_input_iterator <_InputIterator>::value && !__is_forward_iterator<_InputIterator>::value && - is_constructible< + __is_alloc_constructible< + allocator_type, value_type, typename iterator_traits<_InputIterator>::reference>::value, void @@ -586,7 +587,8 @@ typename enable_if < __is_forward_iterator<_ForwardIterator>::value && - is_constructible< + __is_alloc_constructible< + allocator_type, value_type, typename iterator_traits<_ForwardIterator>::reference>::value, void @@ -707,7 +709,8 @@ < __is_input_iterator <_InputIterator>::value && !__is_forward_iterator<_InputIterator>::value && - is_constructible< + __is_alloc_constructible< + allocator_type, value_type, typename iterator_traits<_InputIterator>::reference>::value, iterator @@ -717,7 +720,8 @@ typename enable_if < __is_forward_iterator<_ForwardIterator>::value && - is_constructible< + __is_alloc_constructible< + allocator_type, value_type, typename iterator_traits<_ForwardIterator>::reference>::value, iterator @@ -1364,7 +1368,8 @@ < __is_input_iterator <_InputIterator>::value && !__is_forward_iterator<_InputIterator>::value && - is_constructible< + __is_alloc_constructible< + _Allocator, _Tp, typename iterator_traits<_InputIterator>::reference>::value, void @@ -1381,7 +1386,8 @@ typename enable_if < __is_forward_iterator<_ForwardIterator>::value && - is_constructible< + __is_alloc_constructible< + _Allocator, _Tp, typename iterator_traits<_ForwardIterator>::reference>::value, void @@ -1881,8 +1887,8 @@ < __is_input_iterator <_InputIterator>::value && !__is_forward_iterator<_InputIterator>::value && - is_constructible< - _Tp, + __is_alloc_constructible< + _Allocator, _Tp, typename iterator_traits<_InputIterator>::reference>::value, typename vector<_Tp, _Allocator>::iterator >::type @@ -1938,8 +1944,8 @@ typename enable_if < __is_forward_iterator<_ForwardIterator>::value && - is_constructible< - _Tp, + __is_alloc_constructible< + _Allocator, _Tp, typename iterator_traits<_ForwardIterator>::reference>::value, typename vector<_Tp, _Allocator>::iterator >::type Index: test/libcxx/utilities/memory/allocator.traits/__is_alloc_constructible.pass.cpp =================================================================== --- /dev/null +++ test/libcxx/utilities/memory/allocator.traits/__is_alloc_constructible.pass.cpp @@ -0,0 +1,118 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// template +// struct __is_alloc_constructible; + +#include +#include "tagging_allocator.hpp" + +template +struct ConstructibleFrom { + explicit ConstructibleFrom(Args...) {} +}; + +void test_std_allocator() { + { + using A = std::allocator; // value_type different than constructed type + + static_assert(std::__is_alloc_constructible::value, ""); + + static_assert(std::__is_alloc_constructible::value, ""); + + static_assert(std::__is_alloc_constructible::value, ""); + static_assert(std::__is_alloc_constructible::value, ""); + static_assert(!std::__is_alloc_constructible::value, + "bad argument"); + static_assert(!std::__is_alloc_constructible::value, + "too many arguments"); + A a; + int x = 101; + const int cx = -1; + int dummy; + a.construct(&dummy); + assert(dummy == 0); + a.construct(&dummy, 42); + assert(dummy == 42); + a.construct(&dummy, x); + assert(dummy == x); + a.construct(&dummy, cx); + assert(dummy == cx); + } + { + using A = std::allocator; + static_assert(std::__is_alloc_constructible::value, ""); + static_assert(std::__is_alloc_constructible::value, ""); + static_assert(std::__is_alloc_constructible::value, ""); + static_assert(std::__is_alloc_constructible::value, ""); + static_assert(!std::__is_alloc_constructible::value, + "bad argument"); + static_assert(!std::__is_alloc_constructible::value, + "too many arguments"); + A a; + int x = 101; + const int cx = -1; + int dummy; + a.construct(&dummy); + assert(dummy == 0); + a.construct(&dummy, 42); + assert(dummy == 42); + a.construct(&dummy, x); + assert(dummy == x); + a.construct(&dummy, cx); + assert(dummy == cx); + } + { + using A = std::allocator; + static_assert(std::__is_alloc_constructible::value, ""); + static_assert(std::__is_alloc_constructible::value, ""); + static_assert(std::__is_alloc_constructible::value, ""); + static_assert(std::__is_alloc_constructible::value, ""); + static_assert(!std::__is_alloc_constructible::value, + "bad argument"); + static_assert(!std::__is_alloc_constructible::value, + "too many arguments"); + A a; + int x = 101; + const int cx = -1; + int dummy; + a.construct(&dummy); + assert(dummy == 0); + a.construct(&dummy, 42); + assert(dummy == 42); + a.construct(&dummy, x); + assert(dummy == x); + a.construct(&dummy, cx); + assert(dummy == cx); + } +} + +void test_allocator_traits_tagged_alloc() { + using VT = TaggedValueType; + using A = TaggingAllocator; + A a; + VT* ptr = (VT*)std::malloc(sizeof(VT)); + a.construct(ptr); + a.destroy(ptr); + static_assert(std::__has_allocator_construct::value, ""); + static_assert(std::__is_alloc_constructible::value, ""); + static_assert(std::__is_alloc_destructible::value, ""); + static_assert(!std::is_constructible::value, + "is_constructible requires is_destructible, which is not true"); +} + +int main() +{ + test_std_allocator(); + test_allocator_traits_tagged_alloc(); +} Index: test/std/containers/sequences/vector/tagging_allocator_instantiation.pass.cpp =================================================================== --- /dev/null +++ test/std/containers/sequences/vector/tagging_allocator_instantiation.pass.cpp @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +#include +#include "tagging_allocator.hpp" + +using VT = TaggedValueType; +using Alloc = TaggingAllocator; + +template class std::vector; + +int main() { + std::vector v; + v.reserve(3); + v.emplace_back(); + v.emplace(v.begin()); + v.emplace(v.begin(), 1, 2, 3); +} \ No newline at end of file Index: test/support/tagging_allocator.hpp =================================================================== --- /dev/null +++ test/support/tagging_allocator.hpp @@ -0,0 +1,125 @@ +//===----------------------------------------------------------------------===// +// +// 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 TAGGING_ALLOCATOR_HPP +#define TAGGING_ALLOCATOR_HPP + +# include +# include +# include + +#include "test_macros.h" +struct Tag { }; + +template + class TaggingAllocator + { + public: + using value_type = T; + + TaggingAllocator() = default; + + template + TaggingAllocator(const TaggingAllocator&) { } + + T* + allocate(std::size_t n) { return std::allocator{}.allocate(n); } + + void + deallocate(T* p, std::size_t n) { std::allocator{}.deallocate(p, n); } + + template + + auto construct(U* p, Args&&... args) -> + decltype((void)::new((void*)p) U(Tag{}, std::forward(args)...)) + { ::new((void*)p) U(Tag{}, std::forward(args)...); } + + template + auto destroy(U* p) -> decltype((void)p->~U()) { p->~U(); } + }; + +template + bool + operator==(const TaggingAllocator&, const TaggingAllocator&) + { return true; } + +template + bool + operator!=(const TaggingAllocator&, const TaggingAllocator&) + { return false; } + +template +struct TaggedValueType +{ + // All constructors must be passed the Tag type. + + // DefaultInsertable into vector>, + explicit TaggedValueType(Tag) { } + // CopyInsertable into vector>, + TaggedValueType(Tag, const TaggedValueType&) { } + // MoveInsertable into vector>, and + TaggedValueType(Tag, TaggedValueType&&) { } + + // EmplaceConstructible into vector> from args. + explicit TaggedValueType(Tag, Args...) { } + + // not DefaultConstructible, CopyConstructible or MoveConstructible. + TaggedValueType() = delete; + TaggedValueType(const TaggedValueType&) = delete; + TaggedValueType(TaggedValueType&&) = delete; + + // CopyAssignable. + TaggedValueType& operator=(const TaggedValueType&) { return *this; } + + // MoveAssignable. + TaggedValueType& operator=(TaggedValueType&&) { return *this; } + +private: + // Not Destructible. + ~TaggedValueType() { } + + // Erasable from vector>. + template + friend class TaggingAllocator; +}; + + +template <> +struct TaggedValueType<> +{ + // All constructors must be passed the Tag type. + + // DefaultInsertable into vector>, + explicit TaggedValueType(Tag) { } + // CopyInsertable into vector>, + TaggedValueType(Tag, const TaggedValueType&) { } + // MoveInsertable into vector>, and + TaggedValueType(Tag, TaggedValueType&&) { } + + // not DefaultConstructible, CopyConstructible or MoveConstructible. + TaggedValueType() = delete; + TaggedValueType(const TaggedValueType&) = delete; + TaggedValueType(TaggedValueType&&) = delete; + + // CopyAssignable. + TaggedValueType& operator=(const TaggedValueType&) { return *this; } + + // MoveAssignable. + TaggedValueType& operator=(TaggedValueType&&) { return *this; } + +private: + // Not Destructible. + ~TaggedValueType() { } + + // Erasable from vector>. + template + friend class TaggingAllocator; +}; + +#endif /* TAGGING_ALLOCATOR_HPP */