From f216c5a492bb6a44c305b573b3ff73a82bb4770a Mon Sep 17 00:00:00 2001 From: Loic Gouarin Date: Thu, 29 Oct 2026 18:50:04 +0100 Subject: [PATCH] Simplify svector::grow Both branches of grow() allocated the new buffer and copied the elements into it, and only the heap branch released the old buffer. grow() now does the allocation and the copy once, then releases the old buffer when it is on the heap. The copy uses current_size, the value that sizes the new buffer and sets the new end. The XTENSOR_ASSERT on the result of allocate(), which came after the buffer had been written to, is removed: allocate() throws on failure. The branch taken when the elements are inline was also where GCC 15 at -O3 replaced m_begin with the inline array and, unable to bound the size, warned that the copy reads past it (-Warray-bounds). The size is at most N there, so the read was never out of bounds; the warning goes away with the duplicated branch. Copying current_size elements, rather than recomputing the count from m_end, also keeps GCC 13 from pairing a one-element buffer with a non-empty copy when grow() is inlined into push_back(). --- include/xtensor/containers/xstorage.hpp | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/include/xtensor/containers/xstorage.hpp b/include/xtensor/containers/xstorage.hpp index 26d4a8ccd..11f13d67f 100644 --- a/include/xtensor/containers/xstorage.hpp +++ b/include/xtensor/containers/xstorage.hpp @@ -1328,21 +1328,12 @@ namespace xt new_capacity = min_capacity; } - T* new_alloc; - // is data stack allocated? - if (m_begin == &m_data[0]) - { - new_alloc = m_allocator.allocate(new_capacity); - std::uninitialized_copy(m_begin, m_end, new_alloc); - } - else + T* new_alloc = m_allocator.allocate(new_capacity); + std::uninitialized_copy_n(m_begin, current_size, new_alloc); + if (!on_stack()) { - // If this wasn't grown from the inline copy, grow the allocated space. - new_alloc = m_allocator.allocate(new_capacity); - std::uninitialized_copy(m_begin, m_end, new_alloc); m_allocator.deallocate(m_begin, std::size_t(m_capacity - m_begin)); } - XTENSOR_ASSERT(new_alloc); m_end = new_alloc + current_size; m_begin = new_alloc;