diff --git a/include/Math/Array.hpp b/include/Math/Array.hpp index f2eaeb3..a835736 100644 --- a/include/Math/Array.hpp +++ b/include/Math/Array.hpp @@ -62,11 +62,18 @@ static_assert(Dimension>); static_assert(VectorDimension); static_assert(VectorDimension>); static_assert(!MatrixDimension>); +#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) +template +using DefaultAlloc = std::allocator>; +#else +template +using DefaultAlloc = alloc::Mallocator>; +#endif template , S>(), - class A = alloc::Mallocator>> + class A = DefaultAlloc> struct ManagedArray; template static constexpr auto maxPow10() -> size_t { @@ -969,9 +976,10 @@ struct POLY_MATH_GSL_POINTER ResizeableView : MutArray { this->sz = nz; if constexpr (std::integral) { invariant(U(nz) <= capacity); - if (nz > oz) std::fill(this->data() + oz, this->data() + nz, T{}); - if constexpr (!std::is_trivially_destructible_v) + if constexpr (!std::is_trivially_destructible_v) { for (ptrdiff_t i = nz; i < oz; ++i) this->data()[i].~T(); + for (ptrdiff_t i = oz; i < nz; ++i) new (this->data() + i) T(); + } else if (nz > oz) std::fill(this->data() + oz, this->data() + nz, T{}); } else { static_assert(std::is_trivially_destructible_v, "Resizing matrices holding non-is_trivially_destructible_v " @@ -1043,11 +1051,13 @@ struct POLY_MATH_GSL_POINTER ResizeableView : MutArray { } } constexpr void resizeForOverwrite(S M) { - static_assert( - std::is_trivially_destructible_v, - "resizeForOverwrite for arrays holding non-is_trivially_destructible_v " - "objects is not yet supported."); invariant(U(M) <= U(this->sz)); + if constexpr (!std::is_trivially_destructible_v) { + ptrdiff_t nz = U(M), oz = U(this->sz); + for (ptrdiff_t i = nz; i < oz; ++i) this->data()[i].~T(); + // we set invariant smaller + // for (ptrdiff_t i = oz; i < nz; ++i) new (this->data() + i) T(); + } this->sz = M; } constexpr void resizeForOverwrite(Row<> r) { @@ -1185,8 +1195,16 @@ struct POLY_MATH_GSL_POINTER ReallocView : ResizeableView { maybeDeallocate(newPtr, newCap); invariant(newCapacity > oz); } - std::fill(this->data() + oz, this->data() + nz, T{}); + if constexpr (!std::is_trivially_destructible_v) { + for (ptrdiff_t i = nz; i < oz; ++i) this->data()[i].~T(); + // new T() direct-initializes + // https://en.cppreference.com/w/cpp/language/direct_initialization + for (ptrdiff_t i = oz; i < nz; ++i) new (this->data() + i) T(); + } else if (nz > oz) std::fill(this->data() + oz, this->data() + nz, T{}); } else { + static_assert(std::is_trivially_destructible_v, + "Resizing matrices holding non-is_trivially_destructible_v " + "objects is not yet supported."); static_assert(MatrixDimension, "Can only resize 1 or 2d containers."); U len = U(nz); if (len == 0) return; @@ -1265,6 +1283,13 @@ struct POLY_MATH_GSL_POINTER ReallocView : ResizeableView { constexpr void resizeForOverwrite(S M) { U L = U(M); if (L > U(this->sz)) growUndef(L); + if constexpr (!std::is_trivially_destructible_v) { + ptrdiff_t nz = U(M), oz = U(this->sz); + for (ptrdiff_t i = nz; i < oz; ++i) this->data()[i].~T(); + // new T default-initializes + // https://en.cppreference.com/w/cpp/language/default_initialization + for (ptrdiff_t i = oz; i < nz; ++i) new (this->data() + i) T; + } this->sz = M; } constexpr void resizeForOverwrite(Row<> r) { @@ -1379,6 +1404,8 @@ struct POLY_MATH_GSL_POINTER ReallocView : ResizeableView { // this method should only be called from the destructor // (and the implementation taking the new ptr and capacity) void maybeDeallocate() noexcept { + if constexpr (!std::is_trivially_destructible_v) + for (ptrdiff_t i = 0; i < U(this->sz); ++i) this->data()[i].~T(); if (wasAllocated()) allocator.deallocate(this->data(), this->capacity); } // this method should be called whenever the buffer lives @@ -1420,7 +1447,7 @@ concept AbstractSimilar = /// stack memory. template struct POLY_MATH_GSL_OWNER ManagedArray : ReallocView { - static_assert(std::is_trivially_destructible_v); + // static_assert(std::is_trivially_destructible_v); using BaseT = ReallocView; using U = containers::default_capacity_type_t; using storage_type = typename BaseT::storage_type; diff --git a/include/Math/LinearAlgebra.hpp b/include/Math/LinearAlgebra.hpp index 73b3f5d..23772ad 100644 --- a/include/Math/LinearAlgebra.hpp +++ b/include/Math/LinearAlgebra.hpp @@ -162,7 +162,7 @@ template Row M = B.numRow(); SquareMatrix A{B}; // auto ipiv = Vector{.s = unsigned(M)}; - auto ipiv{vector(alloc::Mallocator{}, ptrdiff_t(M))}; + auto ipiv{vector(math::DefaultAlloc{}, ptrdiff_t(M))}; // Vector ipiv{.s = unsigned(M)}; invariant(ptrdiff_t(ipiv.size()), ptrdiff_t(M)); for (ptrdiff_t k = 0;; ++k) { @@ -197,7 +197,7 @@ template template constexpr auto factImpl(MutSquarePtrMatrix A) { using V = decltype(value(S{})); Row M = A.numRow(); - auto ipiv{vector(alloc::Mallocator{}, ptrdiff_t(M))}; + auto ipiv{vector(math::DefaultAlloc{}, ptrdiff_t(M))}; invariant(ptrdiff_t(ipiv.size()), ptrdiff_t(M)); for (ptrdiff_t k = 0;; ++k) { containers::Pair mi{-1, {}}; diff --git a/include/Math/NormalForm.hpp b/include/Math/NormalForm.hpp index d8afa9c..566cd9b 100644 --- a/include/Math/NormalForm.hpp +++ b/include/Math/NormalForm.hpp @@ -148,7 +148,7 @@ constexpr auto orthogonalizeBang(MutDensePtrMatrix &A) // we try to orthogonalize with respect to as many rows of `A` as we can // prioritizing earlier rows. auto [M, N] = shape(A); - SquareMatrix K{identity(alloc::Mallocator{}, unsigned(M))}; + SquareMatrix K{identity(math::DefaultAlloc{}, unsigned(M))}; Vector included; included.reserve(std::min(ptrdiff_t(M), ptrdiff_t(N))); for (ptrdiff_t i = 0, j = 0; i < std::min(ptrdiff_t(M), ptrdiff_t(N)); ++j) { diff --git a/test/matrix_test.cpp b/test/matrix_test.cpp index 8ed9475..2631ccd 100644 --- a/test/matrix_test.cpp +++ b/test/matrix_test.cpp @@ -346,3 +346,15 @@ TEST(TinyVectorTest, BasicAssertions) { for (auto x : v) s += x; EXPECT_EQ(s, 28); } + +TEST(NonTriviallyDestructible, BasicAssertions) { + Vector y{std::array{204, 205, 206}}; + Vector, 0> x; + x.emplace_back(std::array{2, 3, 4}); + x.emplace_back(std::array{4, 5, 6}); + for (ptrdiff_t i = 0; i < 100; ++i) + x.emplace_back(std::array{6 + 2 * i, 7 + 2 * i, 8 + 2 * i}); + for (ptrdiff_t i = 0; i < x.size(); ++i) + for (ptrdiff_t j = 0; j < 3; ++j) EXPECT_EQ(x[i][j], 2 * (i + 1) + j); + EXPECT_EQ(x.pop_back_val(), y); +}