diff --git a/libcudacxx/include/cuda/std/inplace_vector b/libcudacxx/include/cuda/std/inplace_vector index f88f3ed80e..ff5567b30e 100644 --- a/libcudacxx/include/cuda/std/inplace_vector +++ b/libcudacxx/include/cuda/std/inplace_vector @@ -219,6 +219,7 @@ struct __inplace_vector_destruct_base<_Tp, _Capacity, __inplace_vector_specializ {} }; +// Specialization for non-trivial types. Nothing in here can be constexpr template ()> @@ -249,8 +250,7 @@ struct __inplace_vector_base : __inplace_vector_destruct_base<_Tp, _Capacity, _S _LIBCUDACXX_INLINE_VISIBILITY __inplace_vector_base& operator=(const __inplace_vector_base& __other) noexcept( _CCCL_TRAIT(is_nothrow_copy_constructible, _Tp) && _CCCL_TRAIT(is_nothrow_copy_assignable, _Tp)) { - const auto __diff = static_cast(__other.size() - size()); - if (__diff < 0) + if (__other.size() < size()) { const auto __new_end = _CUDA_VSTD::copy(__other.begin(), __other.end(), begin()); __destroy(__new_end, end()); @@ -266,8 +266,7 @@ struct __inplace_vector_base : __inplace_vector_destruct_base<_Tp, _Capacity, _S _LIBCUDACXX_INLINE_VISIBILITY __inplace_vector_base& operator=(__inplace_vector_base&& __other) noexcept( _CCCL_TRAIT(is_nothrow_move_constructible, _Tp) && _CCCL_TRAIT(is_nothrow_move_assignable, _Tp)) { - const auto __diff = static_cast(__other.size() - size()); - if (__diff < 0) + if (__other.size() < size()) { const auto __new_end = _CUDA_VSTD::move(__other.begin(), __other.end(), begin()); __destroy(__new_end, end()); @@ -333,12 +332,6 @@ struct __inplace_vector_base : __inplace_vector_destruct_base<_Tp, _Capacity, _S } // [containers.sequences.inplace.vector.modifiers], modifiers - _LIBCUDACXX_INLINE_VISIBILITY void __destroy(iterator __first, iterator __last) noexcept - { - _CUDA_VSTD::__destroy(__first, __last); - __change_size(__first - __last); - } - template _LIBCUDACXX_INLINE_VISIBILITY constexpr reference unchecked_emplace_back(_Args&&... __args) noexcept(_CCCL_TRAIT(is_nothrow_constructible, _Tp, _Args...)) @@ -348,6 +341,13 @@ struct __inplace_vector_base : __inplace_vector_destruct_base<_Tp, _Capacity, _S return *__final; } +protected: + _LIBCUDACXX_INLINE_VISIBILITY void __destroy(iterator __first, iterator __last) noexcept + { + _CUDA_VSTD::__destroy(__first, __last); + __change_size(__first - __last); + } + _LIBCUDACXX_TEMPLATE(bool _IsNothrow = _CCCL_TRAIT(is_nothrow_default_constructible, _Tp)) _LIBCUDACXX_REQUIRES(_IsNothrow) _LIBCUDACXX_INLINE_VISIBILITY void __uninitialized_value_construct(iterator __first, iterator __last) noexcept @@ -553,6 +553,7 @@ struct __inplace_vector_base<_Tp, _Capacity, __inplace_vector_specialization::__ return *__final; } +protected: _LIBCUDACXX_INLINE_VISIBILITY constexpr void __destroy(iterator __first, iterator __last) noexcept { __change_size(__first - __last); @@ -664,10 +665,11 @@ struct __inplace_vector_base<_Tp, 0, __inplace_vector_specialization::__empty> { _LIBCUDACXX_UNREACHABLE(); # if defined(_CCCL_COMPILER_MSVC) - return *(end() - 1); + return *begin(); # endif // _CCCL_COMPILER_MSVC } +protected: _LIBCUDACXX_INLINE_VISIBILITY constexpr void __destroy(iterator, iterator) noexcept { _LIBCUDACXX_UNREACHABLE(); @@ -720,33 +722,33 @@ public: constexpr inplace_vector& operator=(const inplace_vector&) = default; constexpr inplace_vector& operator=(inplace_vector&&) = default; - _LIBCUDACXX_INLINE_VISIBILITY constexpr explicit inplace_vector(const size_type __size) + _LIBCUDACXX_INLINE_VISIBILITY constexpr explicit inplace_vector(const size_type __count) : __base() { - if (__size > 0) + if (__count > 0) { - if (_Capacity < __size) + if (_Capacity < __count) { _CUDA_VSTD::__throw_bad_alloc(); } iterator __begin = this->begin(); - this->__uninitialized_value_construct(__begin, __begin + __size); + this->__uninitialized_value_construct(__begin, __begin + __count); } } - _LIBCUDACXX_INLINE_VISIBILITY constexpr inplace_vector(const size_type __size, const _Tp& __value) + _LIBCUDACXX_INLINE_VISIBILITY constexpr inplace_vector(const size_type __count, const _Tp& __value) : __base() { - if (__size > 0) + if (__count > 0) { - if (_Capacity < __size) + if (_Capacity < __count) { _CUDA_VSTD::__throw_bad_alloc(); } iterator __begin = this->begin(); - this->__uninitialized_fill(__begin, __begin + __size, __value); + this->__uninitialized_fill(__begin, __begin + __count, __value); } } @@ -832,10 +834,10 @@ public: _LIBCUDACXX_INLINE_VISIBILITY constexpr inplace_vector(_Range&& __range) : __base() { - const auto __size = static_cast(_CUDA_VRANGES::distance(__range.begin(), __range.end())); - if (__size > 0) + const auto __count = static_cast(_CUDA_VRANGES::distance(__range.begin(), __range.end())); + if (__count > 0) { - if (_Capacity < __size) + if (_Capacity < __count) { _CUDA_VSTD::__throw_bad_alloc(); } @@ -847,52 +849,52 @@ public: _LIBCUDACXX_INLINE_VISIBILITY constexpr inplace_vector& operator=(initializer_list<_Tp> __ilist) { + const auto __count = __ilist.size(); _CCCL_IF_CONSTEXPR (_Capacity == 0) { - _LIBCUDACXX_ASSERT(__size == 0, "Cannot assign to inplace_vector with zero capacity "); + _LIBCUDACXX_ASSERT(__count == 0, "Cannot assign to inplace_vector with zero capacity "); return *this; } - if (_Capacity < __ilist.size()) + if (_Capacity < __count) { _CUDA_VSTD::__throw_bad_alloc(); } - const auto __diff = static_cast(__ilist.size() - this->size()); - if (__diff < 0) + const auto __size = this->size(); + if (__count < __size) { const iterator __new_end = _CUDA_VSTD::copy(__ilist.begin(), __ilist.end(), this->begin()); this->__destroy(__new_end, this->end()); } else { - _CUDA_VSTD::copy(__ilist.begin(), __ilist.begin() + this->size(), this->begin()); - this->__uninitialized_copy(__ilist.begin() + this->size(), __ilist.end(), this->end()); + _CUDA_VSTD::copy(__ilist.begin(), __ilist.begin() + __size, this->begin()); + this->__uninitialized_copy(__ilist.begin() + __size, __ilist.end(), this->end()); } return *this; } // inplace_vector.assign - _LIBCUDACXX_INLINE_VISIBILITY constexpr void assign(const size_type __size, const _Tp& __value) + _LIBCUDACXX_INLINE_VISIBILITY constexpr void assign(const size_type __count, const _Tp& __value) { _CCCL_IF_CONSTEXPR (_Capacity == 0) { - _LIBCUDACXX_ASSERT(__size == 0, "Cannot assign to inplace_vector with zero capacity "); + _LIBCUDACXX_ASSERT(__count == 0, "Cannot assign to inplace_vector with zero capacity "); return; } - const auto __diff = static_cast(__size - this->size()); - if (__diff < 0) + const pointer __begin = this->begin(); + const iterator __end = this->end(); + if (__count < this->size()) { - const pointer __begin = this->begin(); - _CUDA_VSTD::fill(__begin, __begin + __size, __value); - this->__destroy(__begin + __size, this->end()); + _CUDA_VSTD::fill(__begin, __begin + __count, __value); + this->__destroy(__begin + __count, __end); } else { - const iterator __end = this->end(); - _CUDA_VSTD::fill(this->begin(), __end, __value); - this->__uninitialized_fill(__end, __end + __diff, __value); + _CUDA_VSTD::fill(__begin, __end, __value); + this->__uninitialized_fill(__end, __begin + __count, __value); } } @@ -934,7 +936,8 @@ public: return; } - const auto __diff = static_cast(_CUDA_VSTD::distance(__first, __last) - this->size()); + const auto __diff = + static_cast(_CUDA_VSTD::distance(__first, __last)) - static_cast(this->size()); if (__diff < 0) { const iterator __new_end = _CUDA_VSTD::copy(__first, __last, this->begin()); @@ -956,7 +959,7 @@ public: return; } - const auto __diff = static_cast(__ilist.size() - this->size()); + const auto __diff = static_cast(__ilist.size()) - static_cast(this->size()); if (__diff < 0) { const iterator __new_end = _CUDA_VSTD::copy(__ilist.begin(), __ilist.end(), this->begin()); @@ -1014,7 +1017,7 @@ public: const auto __first = __range.begin(); const auto __last = __unwrap_end(__range); - const auto __diff = static_cast(__size - this->size()); + const auto __diff = static_cast(__size) - static_cast(this->size()); if (__diff < 0) { const iterator __new_end = _CUDA_VSTD::copy(__first, __last, this->begin()); @@ -1042,7 +1045,7 @@ public: return; } - const auto __diff = static_cast(__size - this->size()); + const auto __diff = static_cast(__size) - static_cast(this->size()); if (__diff < 0) { const iterator __new_end = _CUDA_VSTD::copy(__first, __last, this->begin()); @@ -1493,6 +1496,11 @@ public: _LIBCUDACXX_INLINE_VISIBILITY constexpr _CUDA_VRANGES::iterator_t<_Range> try_append_range(_Range&& __range) noexcept(_CCCL_TRAIT(is_nothrow_move_constructible, _Tp)) { + _CCCL_IF_CONSTEXPR (_Capacity == 0) + { + return __range.begin(); + } + const auto __capacity = _Capacity - this->size(); const auto __size = _CUDA_VRANGES::size(__range); const auto __diff = __size < __capacity ? __size : __capacity; @@ -1509,6 +1517,11 @@ public: _LIBCUDACXX_INLINE_VISIBILITY constexpr _CUDA_VRANGES::iterator_t<_Range> try_append_range(_Range&& __range) noexcept(_CCCL_TRAIT(is_nothrow_move_constructible, _Tp)) { + _CCCL_IF_CONSTEXPR (_Capacity == 0) + { + return __range.begin(); + } + const auto __capacity = static_cast(_Capacity - this->size()); auto __first = __range.begin(); const auto __size = static_cast(_CUDA_VRANGES::distance(__first, __unwrap_end(__range))); @@ -1583,19 +1596,27 @@ public: _LIBCUDACXX_INLINE_VISIBILITY constexpr void clear() noexcept { + _CCCL_IF_CONSTEXPR (_Capacity == 0) + { + return; + } this->__destroy(this->begin(), this->end()); } - _LIBCUDACXX_INLINE_VISIBILITY constexpr void resize(const size_type __size) + _LIBCUDACXX_INLINE_VISIBILITY constexpr void resize(const size_type __count) { - const auto __diff = static_cast(__size - this->size()); - if (__diff < 0) + const auto __diff = static_cast(__count) - static_cast(this->size()); + if (__diff == 0) + { + return; + } + else if (__diff < 0) { - this->__destroy(this->begin() + __size, this->end()); + this->__destroy(this->begin() + __count, this->end()); } else { - if (_Capacity < __size) + if (_Capacity < __count) { _CUDA_VSTD::__throw_bad_alloc(); } @@ -1605,16 +1626,20 @@ public: } } - _LIBCUDACXX_INLINE_VISIBILITY constexpr void resize(const size_type __size, const _Tp& __value) + _LIBCUDACXX_INLINE_VISIBILITY constexpr void resize(const size_type __count, const _Tp& __value) { - const auto __diff = static_cast(__size - this->size()); - if (__diff < 0) + const auto __diff = static_cast(__count) - static_cast(this->size()); + if (__diff == 0) + { + return; + } + else if (__diff < 0) { - this->__destroy(this->begin() + __size, this->end()); + this->__destroy(this->begin() + __count, this->end()); } else { - if (_Capacity < __size) + if (_Capacity < __count) { _CUDA_VSTD::__throw_bad_alloc(); } @@ -1624,9 +1649,9 @@ public: } } - _LIBCUDACXX_INLINE_VISIBILITY static constexpr void reserve(const size_type __size) + _LIBCUDACXX_INLINE_VISIBILITY static constexpr void reserve(const size_type __count) { - if (_Capacity < __size) + if (_Capacity < __count) { _CUDA_VSTD::__throw_bad_alloc(); } @@ -1720,6 +1745,10 @@ public: _LIBCUDACXX_INLINE_VISIBILITY friend constexpr size_type erase(inplace_vector& __cont, const _Up& __value) noexcept(_CCCL_TRAIT(is_nothrow_move_assignable, _Tp)) { + _CCCL_IF_CONSTEXPR (_Capacity == 0) + { + return 0; + } const pointer __old_end = __cont.end(); const iterator __new_end = _CUDA_VSTD::remove(__cont.begin(), __old_end, __value); __cont.__destroy(__new_end, __old_end); @@ -1730,6 +1759,10 @@ public: _LIBCUDACXX_INLINE_VISIBILITY friend constexpr size_type erase_if(inplace_vector& __cont, _Pred __pred) noexcept(_CCCL_TRAIT(is_nothrow_move_assignable, _Tp)) { + _CCCL_IF_CONSTEXPR (_Capacity == 0) + { + return 0; + } const pointer __old_end = __cont.end(); const iterator __new_end = _CUDA_VSTD::remove_if(__cont.begin(), __old_end, _CUDA_VSTD::move(__pred)); __cont.__destroy(__new_end, __old_end); diff --git a/libcudacxx/test/libcudacxx/std/containers/sequences/inplace_vector/access.pass.cpp b/libcudacxx/test/libcudacxx/std/containers/sequences/inplace_vector/access.pass.cpp index 9bdf696de7..6b0296db2b 100644 --- a/libcudacxx/test/libcudacxx/std/containers/sequences/inplace_vector/access.pass.cpp +++ b/libcudacxx/test/libcudacxx/std/containers/sequences/inplace_vector/access.pass.cpp @@ -74,6 +74,7 @@ __host__ __device__ constexpr void test() __host__ __device__ constexpr bool test() { test(); + test(); if (!cuda::std::__libcpp_is_constant_evaluated()) { diff --git a/libcudacxx/test/libcudacxx/std/containers/sequences/inplace_vector/assign.pass.cpp b/libcudacxx/test/libcudacxx/std/containers/sequences/inplace_vector/assign.pass.cpp index ccf9089cab..55e7cb118e 100644 --- a/libcudacxx/test/libcudacxx/std/containers/sequences/inplace_vector/assign.pass.cpp +++ b/libcudacxx/test/libcudacxx/std/containers/sequences/inplace_vector/assign.pass.cpp @@ -32,32 +32,36 @@ _CCCL_DIAG_SUPPRESS_MSVC(5246) template class Range> __host__ __device__ constexpr void test_ranges() { - { - cuda::std::inplace_vector input_range_empty{}; - input_range_empty.assign_range(Range{}); - assert(input_range_empty.empty()); + { // inplace_vector::assign_range with an empty input + cuda::std::inplace_vector inplace_vector{}; + inplace_vector.assign_range(Range{}); + assert(inplace_vector.empty()); } - { - cuda::std::inplace_vector input_range_shrink_empty{T(1), T(42), T(1337), T(0)}; - input_range_shrink_empty.assign_range(Range{}); - assert(input_range_shrink_empty.empty()); + { // inplace_vector::assign_range with an empty input + cuda::std::inplace_vector inplace_vector{}; + inplace_vector.assign_range(Range{}); + assert(inplace_vector.empty()); } - { - const cuda::std::array expected = {T(42), T(42)}; - cuda::std::inplace_vector input_range_shrink{T(1), T(42), T(1337), T(0)}; - input_range_shrink.assign_range(Range{T(42), T(42)}); - assert(!input_range_shrink.empty()); - assert(cuda::std::equal(input_range_shrink.begin(), input_range_shrink.end(), expected.begin(), expected.end())); + { // inplace_vector::assign_range with an empty input, shrinking + cuda::std::inplace_vector inplace_vector{T(1), T(42), T(1337), T(0)}; + inplace_vector.assign_range(Range{}); + assert(inplace_vector.empty()); } - { - const cuda::std::array expected = {T(42), T(42), T(42), T(42), T(42), T(42)}; - cuda::std::inplace_vector input_range_grow{T(1), T(42), T(1337), T(0)}; - input_range_grow.assign_range(Range{T(42), T(42), T(42), T(42), T(42), T(42)}); - assert(!input_range_grow.empty()); - assert(cuda::std::equal(input_range_grow.begin(), input_range_grow.end(), expected.begin(), expected.end())); + { // inplace_vector::assign_range with a non-empty input, shrinking + cuda::std::inplace_vector inplace_vector{T(1), T(42), T(1337), T(0)}; + inplace_vector.assign_range(Range{T(42), T(42)}); + assert(!inplace_vector.empty()); + assert(equal_range(inplace_vector, cuda::std::array{T(42), T(42)})); + } + + { // inplace_vector::assign_range with a non-empty input, growing + cuda::std::inplace_vector inplace_vector{T(1), T(42), T(1337), T(0)}; + inplace_vector.assign_range(Range{T(42), T(1), T(42), T(1337), T(0), T(42)}); + assert(!inplace_vector.empty()); + assert(equal_range(inplace_vector, cuda::std::array{T(42), T(1), T(42), T(1337), T(0), T(42)})); } } #endif // TEST_STD_VER >= 2017 && !defined(TEST_COMPILER_MSVC_2017) @@ -110,7 +114,7 @@ __host__ __device__ constexpr void test() cuda::std::inplace_vector size_value_shrink{T(1), T(42), T(1337), T(0)}; size_value_shrink.assign(2, T(42)); assert(!size_value_shrink.empty()); - assert(cuda::std::equal(size_value_shrink.begin(), size_value_shrink.end(), expected.begin(), expected.end())); + assert(equal_range(size_value_shrink, expected)); } { @@ -118,7 +122,7 @@ __host__ __device__ constexpr void test() cuda::std::inplace_vector size_value_grow{T(1), T(42), T(1337), T(0)}; size_value_grow.assign(6, T(42)); assert(!size_value_grow.empty()); - assert(cuda::std::equal(size_value_grow.begin(), size_value_grow.end(), expected.begin(), expected.end())); + assert(equal_range(size_value_grow, expected)); } { @@ -143,8 +147,7 @@ __host__ __device__ constexpr void test() cuda::std::inplace_vector input_iter_iter_shrink{T(1), T(42), T(1337), T(0)}; input_iter_iter_shrink.assign(iter{expected.begin()}, iter{expected.end()}); assert(!input_iter_iter_shrink.empty()); - assert( - cuda::std::equal(input_iter_iter_shrink.begin(), input_iter_iter_shrink.end(), expected.begin(), expected.end())); + assert(equal_range(input_iter_iter_shrink, expected)); } { @@ -153,8 +156,7 @@ __host__ __device__ constexpr void test() cuda::std::inplace_vector input_iter_iter_grow{T(1), T(42), T(1337), T(0)}; input_iter_iter_grow.assign(iter{expected.begin()}, iter{expected.end()}); assert(!input_iter_iter_grow.empty()); - assert( - cuda::std::equal(input_iter_iter_grow.begin(), input_iter_iter_grow.end(), expected.begin(), expected.end())); + assert(equal_range(input_iter_iter_grow, expected)); } { @@ -176,7 +178,7 @@ __host__ __device__ constexpr void test() cuda::std::inplace_vector iter_iter_shrink{T(1), T(42), T(1337), T(0)}; iter_iter_shrink.assign(expected.begin(), expected.end()); assert(!iter_iter_shrink.empty()); - assert(cuda::std::equal(iter_iter_shrink.begin(), iter_iter_shrink.end(), expected.begin(), expected.end())); + assert(equal_range(iter_iter_shrink, expected)); } { @@ -184,7 +186,7 @@ __host__ __device__ constexpr void test() cuda::std::inplace_vector iter_iter_grow{T(1), T(42), T(1337), T(0)}; iter_iter_grow.assign(expected.begin(), expected.end()); assert(!iter_iter_grow.empty()); - assert(cuda::std::equal(iter_iter_grow.begin(), iter_iter_grow.end(), expected.begin(), expected.end())); + assert(equal_range(iter_iter_grow, expected)); } { @@ -206,7 +208,7 @@ __host__ __device__ constexpr void test() cuda::std::inplace_vector init_list_shrink{T(1), T(42), T(1337), T(0)}; init_list_shrink.assign(expected); assert(!init_list_shrink.empty()); - assert(cuda::std::equal(init_list_shrink.begin(), init_list_shrink.end(), expected.begin(), expected.end())); + assert(equal_range(init_list_shrink, expected)); } { @@ -214,7 +216,7 @@ __host__ __device__ constexpr void test() cuda::std::inplace_vector init_list_grow{T(1), T(42), T(1337), T(0)}; init_list_grow.assign(expected); assert(!init_list_grow.empty()); - assert(cuda::std::equal(init_list_grow.begin(), init_list_grow.end(), expected.begin(), expected.end())); + assert(equal_range(init_list_grow, expected)); } #if TEST_STD_VER >= 2017 && !defined(TEST_COMPILER_MSVC_2017) @@ -228,6 +230,7 @@ __host__ __device__ constexpr void test() __host__ __device__ constexpr bool test() { test(); + test(); if (!cuda::std::__libcpp_is_constant_evaluated()) { @@ -240,15 +243,15 @@ __host__ __device__ constexpr bool test() } #ifndef TEST_HAS_NO_EXCEPTIONS +template