diff --git a/dynarray.h b/dynarray.h index 21c00dc6..43cfe182 100644 --- a/dynarray.h +++ b/dynarray.h @@ -92,19 +92,19 @@ class dynarray using const_reverse_iterator = std::reverse_iterator; - constexpr dynarray() noexcept(noexcept(Alloc{})) : _m(Alloc{}) {} - constexpr explicit dynarray(const Alloc & a) noexcept : _m(a) {} + constexpr dynarray() noexcept(noexcept(Alloc{})) : dynarray(Alloc{}) {} + constexpr explicit dynarray(Alloc a) noexcept : _m(a) {} //! Construct empty dynarray with space reserved for exactly capacity elements - dynarray(reserve_tag, size_type capacity, const Alloc & a = Alloc{}) : _m(a) { _initReserve(capacity); } + dynarray(reserve_tag, size_type capacity, Alloc a = Alloc{}) : _m(a) { _initReserve(capacity); } /** @brief Default-initializes elements, can be significantly faster if T is scalar or has trivial default constructor * * @copydetails resize_for_overwrite(size_type) */ - dynarray(size_type size, for_overwrite_t, const Alloc & a = Alloc{}); + dynarray(size_type size, for_overwrite_t, Alloc a = Alloc{}); //! (Value-initializes elements, same as std::vector) - explicit dynarray(size_type size, const Alloc & a = Alloc{}); - dynarray(size_type size, const T & val, const Alloc & a = Alloc{}) : _m(a) { append(size, val); } + explicit dynarray(size_type size, Alloc a = Alloc{}); + dynarray(size_type size, const T & val, Alloc a = Alloc{}) : _m(a) { append(size, val); } /** @brief Equivalent to `std::vector(begin(r), end(r), a)`, where `end(r)` is not needed if `r.size()` exists * @@ -117,15 +117,15 @@ class dynarray @endcode */ template< typename InputRange, typename /*EnableIfRange*/ = iterator_t > - explicit dynarray(InputRange && r, const Alloc & a = Alloc{}) : _m(a) { append(r); } + explicit dynarray(InputRange && r, Alloc a = Alloc{}) : _m(a) { append(r); } - dynarray(std::initializer_list il, const Alloc & a = Alloc{}) : _m(a) { append(il); } + dynarray(std::initializer_list il, Alloc a = Alloc{}) : _m(a) { append(il); } - dynarray(dynarray && other) noexcept : _m(std::move(other._m)) {} - dynarray(dynarray && other, const Alloc & a); - dynarray(const dynarray & other) : dynarray(other, - _alloTrait::select_on_container_copy_construction(other._m)) {} - dynarray(const dynarray & other, const Alloc & a) : _m(a) { append(other); } + dynarray(dynarray && other) noexcept : _m(std::move(other._m)) {} + dynarray(dynarray && other, Alloc a); + dynarray(const dynarray & other) : dynarray(other, + _alloTrait::select_on_container_copy_construction(other._m)) {} + dynarray(const dynarray & other, Alloc a) : _m(a) { append(other); } ~dynarray() noexcept; @@ -294,22 +294,22 @@ class dynarray private: using _allocateWrap = _detail::DebugAllocateWrapper; - using _internBase = _detail::DynarrBase; + using _internBase = _detail::DynarrBase; using _debugSizeUpdater = _detail::DebugSizeInHeaderUpdater<_internBase>; + using _alloc_7KQWe = Alloc; // guarding against name collision due to inheritance (MSVC) - template< typename > // template to allow constexpr constructor when Alloc copy constructor is not constexpr - struct _memOwner : public _internBase, public allocator_type + struct _memOwner : public _internBase, public _alloc_7KQWe { - using _internBase::data; // Owning pointer to beginning of data buffer - using _internBase::end; // Pointer to one past the back object - using _internBase::reservEnd; // Pointer to end of allocated memory + using ::oel::_detail::DynarrBase::data; // owner + using ::oel::_detail::DynarrBase::end; + using ::oel::_detail::DynarrBase::reservEnd; - constexpr _memOwner(const allocator_type & a) - : _internBase(), allocator_type(a) { + constexpr _memOwner(_alloc_7KQWe & a) noexcept + : ::oel::_detail::DynarrBase{}, _alloc_7KQWe{std::move(a)} { } _memOwner(_memOwner && other) noexcept - : _internBase(other), allocator_type(std::move(other)) + : ::oel::_detail::DynarrBase{other}, _alloc_7KQWe{std::move(other)} { other.reservEnd = other.end = other.data = nullptr; } @@ -317,21 +317,18 @@ class dynarray ~_memOwner() { if (data) - _allocateWrap::dealloc(*this, data, reservEnd - data); + ::oel::_detail::DebugAllocateWrapper<_alloc_7KQWe, pointer>::dealloc(*this, data, reservEnd - data); } - }; - _memOwner _m; // the only non-static data member + } + _m; // the only non-static data member - // Should be very careful with potential name collisions because of inheriting from allocator - struct _scopedPtr : private allocator_type + struct _scopedPtr : private _alloc_7KQWe { pointer data; // owner pointer bufEnd; - _scopedPtr(const allocator_type & a, size_type const capPrechecked) - : allocator_type(a), - data{_allocateWrap::allocate(*this, capPrechecked)}, - bufEnd{data + capPrechecked} { + _scopedPtr(const _alloc_7KQWe & a, pointer buf, size_type capacity) + : _alloc_7KQWe{a}, data{buf}, bufEnd{buf + capacity} { } _scopedPtr(_scopedPtr &&) = delete; @@ -339,11 +336,11 @@ class dynarray ~_scopedPtr() { if (data) - _allocateWrap::dealloc(*this, data, bufEnd - data); + ::oel::_detail::DebugAllocateWrapper<_alloc_7KQWe, pointer>::dealloc(*this, data, bufEnd - data); } }; - using _uninitFill = _detail::UninitFill; + using _uninitFill = _detail::UninitFill<_memOwner>; void _resetData(T *const newData) { @@ -576,7 +573,7 @@ class dynarray InputIter _append(InputIter src, size_type const n) { return _appendImpl( - [src_ = std::move(src)](T * dest, size_type n_, decltype(_m) & alloc) mutable + [src_ = std::move(src)](T * dest, size_type n_, _memOwner & alloc) mutable { return _detail::UninitCopy(std::move(src_), dest, dest + n_, alloc); }, @@ -600,7 +597,8 @@ class dynarray template< typename InsertHelper, typename... Args > T * _insertRealloc(T *const pos, Args... args) { - _scopedPtr newBuf{_m, InsertHelper::calcCap(*this, args...)}; + auto const newCap = InsertHelper::calcCap(*this, args...); + _scopedPtr newBuf{_m, _allocateWrap::allocate(_m, newCap), newCap}; size_type const nBefore = pos - data(); T *const newPos = newBuf.data + nBefore; @@ -624,7 +622,7 @@ class dynarray } template< typename... Args > - static T * construct(decltype(_m) & alloc, T *const newPos, Args... args) + static T * construct(_memOwner & alloc, T *const newPos, Args... args) { _alloTrait::construct(alloc, newPos, static_cast(args)...); return newPos + 1; @@ -640,7 +638,7 @@ class dynarray } template< typename InputIter, typename > - static T * construct(decltype(_m) & alloc, T *const newPos, InputIter first, size_type count) + static T * construct(_memOwner & alloc, T *const newPos, InputIter first, size_type count) { T *const dLast = newPos + count; _detail::UninitCopy(std::move(first), newPos, dLast, alloc); @@ -757,10 +755,11 @@ inline T & dynarray::emplace_back(Args &&... args) & template< typename T, typename Alloc > -dynarray::dynarray(dynarray && other, const Alloc & a) - : _m(a) +dynarray::dynarray(dynarray && other, Alloc a) + : _m(a) // moves from a { - OEL_CONST_COND if (!_alloTrait::is_always_equal::value and a != other._m) + Alloc & myA = _m; + OEL_CONST_COND if (!_alloTrait::is_always_equal::value and myA != other._m) append(other | view::move); else _moveInternBase(other._m); @@ -790,7 +789,7 @@ dynarray & dynarray::operator =(dynarray && other) & } template< typename T, typename Alloc > -dynarray::dynarray(size_type n, for_overwrite_t, const Alloc & a) +dynarray::dynarray(size_type n, for_overwrite_t, Alloc a) : _m(a) { _debugSizeUpdater guard{_m}; @@ -801,7 +800,7 @@ dynarray::dynarray(size_type n, for_overwrite_t, const Alloc & a) } template< typename T, typename Alloc > -dynarray::dynarray(size_type n, const Alloc & a) +dynarray::dynarray(size_type n, Alloc a) : _m(a) { _debugSizeUpdater guard{_m}; @@ -851,7 +850,7 @@ inline void dynarray::append(size_type n, const T & val) { _detail::ForwardT val_; - auto operator()(T * dest, size_type n_, decltype(_m) & alloc) const + auto operator()(T * dest, size_type n_, _memOwner & alloc) const { _uninitFill::call(dest, dest + n_, alloc, val_); return nullptr; // returned by _appendImpl diff --git a/unit_test/dynarray_construct_assignop_swap_gtest.cpp b/unit_test/dynarray_construct_assignop_swap_gtest.cpp index b24c27f5..4547b6e5 100644 --- a/unit_test/dynarray_construct_assignop_swap_gtest.cpp +++ b/unit_test/dynarray_construct_assignop_swap_gtest.cpp @@ -56,9 +56,17 @@ struct NonConstexprAlloc : oel::allocator }; } +#if __cpp_constinit +void testConstInitCompile() +{ + constinit static dynarray d; +} +#endif + void testNonConstexprCompile() { - dynarray d; + static dynarray d; + [[maybe_unused]] auto d2 = dynarray(NonConstexprAlloc{}); } TEST_F(dynarrayConstructTest, emptyBracesArg) diff --git a/unit_test/test_classes.h b/unit_test/test_classes.h index b834e135..52682327 100644 --- a/unit_test/test_classes.h +++ b/unit_test/test_classes.h @@ -257,13 +257,22 @@ struct TrackingAllocator : TrackingAllocatorBase new(raw) T(std::forward(args)...);; } + // Testing collision with internal names in dynarray + using allocator_type = TrackingAllocatorBase; using Alloc = void; + struct oel {}; + struct _detail {}; + struct _internBase {}; + struct _allocateWrap + { + void dealloc(TrackingAllocator, void *, std::size_t); + }; }; template struct StatefulAllocator : std::conditional_t< UseConstruct, TrackingAllocator, TrackingAllocatorBase > { - using propagate_on_container_move_assignment = oel::bool_constant; + using propagate_on_container_move_assignment = std::bool_constant; int id; @@ -272,8 +281,6 @@ struct StatefulAllocator : std::conditional_t< UseConstruct, TrackingAllocator