From c91858b2e44fbb0a04ce15fd001ec5e6b0c4856b Mon Sep 17 00:00:00 2001 From: Ole Erik Peistorpet Date: Thu, 23 Sep 2021 21:59:14 +0200 Subject: [PATCH] Changed OEL_DEBUG_HEADER_OF to function, got rid of _makeIter Also refined dynarray_iterator a little. And [[nodiscard]] dynarray::empty --- auxi/allocate_with_header.h | 19 ++++---- auxi/dynarray_iterator.h | 69 ++++++++++++++++-------------- dynarray.h | 43 +++++++------------ unit_test/dynarray_other_gtest.cpp | 15 +++++++ 4 files changed, 80 insertions(+), 66 deletions(-) diff --git a/auxi/allocate_with_header.h b/auxi/allocate_with_header.h index f8cc838a..029df11b 100644 --- a/auxi/allocate_with_header.h +++ b/auxi/allocate_with_header.h @@ -21,14 +21,16 @@ namespace oel::_detail inline constexpr DebugAllocationHeader headerNoAllocation{}; - #define OEL_DEBUG_HEADER_OF(ptr) ( (DebugAllocationHeader *)static_cast(ptr) - 1) - #define OEL_DEBUG_HEADER_OF_C(ptr) ((const DebugAllocationHeader *)static_cast(ptr) - 1) + OEL_ALWAYS_INLINE inline DebugAllocationHeader * DebugHeaderOf(void * p) + { + return static_cast(p) - 1; + } template< typename T > inline bool HasValidIndex(const T * arrayElem, const DebugAllocationHeader & h) { - size_t index = arrayElem - reinterpret_cast(&h + 1); - return index < h.nObjects; + auto index = arrayElem - reinterpret_cast(&h + 1); + return static_cast(index) < h.nObjects; } template< typename Alloc, typename Ptr > @@ -45,7 +47,8 @@ namespace oel::_detail { p += sizeForHeader; - auto const h = OEL_DEBUG_HEADER_OF(p); + auto const h = _detail::DebugHeaderOf(p); + // Take address, set highest and lowest bits for a hopefully unique bit pattern to compare later constexpr auto maxMinBits = ~(~std::uintptr_t{} >> 1) | 1u; new(h) DebugAllocationHeader{reinterpret_cast(&a) | maxMinBits, 0}; @@ -68,7 +71,7 @@ namespace oel::_detail #if OEL_MEM_BOUND_DEBUG_LVL if (p) { // volatile to make sure the write isn't optimized away - static_cast(OEL_DEBUG_HEADER_OF(p)->id) = 0; + static_cast(_detail::DebugHeaderOf(p)->id) = 0; p -= sizeForHeader; } n += sizeForHeader; @@ -82,7 +85,7 @@ namespace oel::_detail static void dealloc(Alloc & a, Ptr p, size_t n) noexcept(noexcept( a.deallocate(p, n) )) { #if OEL_MEM_BOUND_DEBUG_LVL - static_cast(OEL_DEBUG_HEADER_OF(p)->id) = 0; + static_cast(_detail::DebugHeaderOf(p)->id) = 0; p -= sizeForHeader; n += sizeForHeader; #endif @@ -102,7 +105,7 @@ namespace oel::_detail { if (container.data) { - auto h = OEL_DEBUG_HEADER_OF(container.data); + auto h = _detail::DebugHeaderOf(container.data); h->nObjects = container.end - container.data; } } diff --git a/auxi/dynarray_iterator.h b/auxi/dynarray_iterator.h index 2f70ec90..ffca7a04 100644 --- a/auxi/dynarray_iterator.h +++ b/auxi/dynarray_iterator.h @@ -1,6 +1,6 @@ #pragma once -// Copyright 2014, 2015 Ole Erik Peistorpet +// Copyright 2015 Ole Erik Peistorpet // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -35,9 +35,9 @@ class dynarray_iterator #if OEL_MEM_BOUND_DEBUG_LVL >= 2 // Test for iterator pair pointing to same container - #define OEL_ITER_CHECK_COMPATIBLE(other) OEL_ASSERT(_allocationId == other._allocationId) + #define OEL_ITER_CHECK_COMPATIBLE(a, b) OEL_ASSERT((a)._allocationId == (b)._allocationId) #else - #define OEL_ITER_CHECK_COMPATIBLE(other) + #define OEL_ITER_CHECK_COMPATIBLE(a, b) #endif public: @@ -71,26 +71,26 @@ class dynarray_iterator } dynarray_iterator & operator++() & OEL_ALWAYS_INLINE - { // preincrement + { ++_pElem; return *this; } dynarray_iterator operator++(int) & - { // postincrement + { // post-increment auto tmp = *this; ++_pElem; return tmp; } dynarray_iterator & operator--() & OEL_ALWAYS_INLINE - { // predecrement + { --_pElem; return *this; } dynarray_iterator operator--(int) & - { // postdecrement + { // post-decrement auto tmp = *this; --_pElem; return tmp; @@ -108,66 +108,67 @@ class dynarray_iterator return *this; } - friend dynarray_iterator operator +(difference_type offset, dynarray_iterator it) + [[nodiscard]] friend dynarray_iterator operator +(difference_type offset, dynarray_iterator it) { - return it += offset; + it._pElem += offset; + return it; } - friend dynarray_iterator operator +(dynarray_iterator it, difference_type offset) + [[nodiscard]] friend dynarray_iterator operator +(dynarray_iterator it, difference_type offset) { - return it += offset; + it._pElem += offset; + return it; } - friend dynarray_iterator operator -(dynarray_iterator it, difference_type offset) + [[nodiscard]] friend dynarray_iterator operator -(dynarray_iterator it, difference_type offset) { - return it -= offset; + it._pElem -= offset; + return it; } - difference_type operator -(const const_iterator & right) const - { // difference of iterators - OEL_ITER_CHECK_COMPATIBLE(right); - return _pElem - right._pElem; + friend difference_type operator -(const dynarray_iterator & left, const dynarray_iterator & right) + { + OEL_ITER_CHECK_COMPATIBLE(left, right); + return left._pElem - right._pElem; } reference operator[](difference_type offset) const { - auto tmp = *this; - tmp += offset; // not operator + to save a call in non-optimized builds - return *tmp; + return *(*this + offset); } template< typename Ptr1 > bool operator==(const dynarray_iterator & right) const { - OEL_ITER_CHECK_COMPATIBLE(right); + OEL_ITER_CHECK_COMPATIBLE(*this, right); return _pElem == right._pElem; } template< typename Ptr1 > bool operator!=(const dynarray_iterator & right) const { - OEL_ITER_CHECK_COMPATIBLE(right); + OEL_ITER_CHECK_COMPATIBLE(*this, right); return _pElem != right._pElem; } template< typename Ptr1 > bool operator <(const dynarray_iterator & right) const { - OEL_ITER_CHECK_COMPATIBLE(right); + OEL_ITER_CHECK_COMPATIBLE(*this, right); return _pElem < right._pElem; } template< typename Ptr1 > bool operator >(const dynarray_iterator & right) const { - OEL_ITER_CHECK_COMPATIBLE(right); + OEL_ITER_CHECK_COMPATIBLE(*this, right); return _pElem > right._pElem; } template< typename Ptr1 > bool operator<=(const dynarray_iterator & right) const { - return !(*this > right); + return !(right < *this); } template< typename Ptr1 > @@ -212,16 +213,22 @@ struct std::pointer_traits< oel::dynarray_iterator > namespace oel::_detail { - template< typename Ptr > - dynarray_iterator MakeDynarrayIter(Ptr const pos, Ptr const begin, const void * parent) noexcept + template< typename Ptr, typename P2 > + auto MakeDynarrIter(const DynarrBase & parent, Ptr const pos) noexcept { - if (begin) + #if OEL_MEM_BOUND_DEBUG_LVL + if (parent.data) { - auto const h = OEL_DEBUG_HEADER_OF_C(begin); - return {pos, h, h->id}; + auto const h = _detail::DebugHeaderOf(parent.data); + return dynarray_iterator{pos, h, h->id}; } else - { return {pos, &_detail::headerNoAllocation, reinterpret_cast(parent)}; + { auto id = reinterpret_cast(&parent); + return dynarray_iterator{pos, &_detail::headerNoAllocation, id}; } + #else + (void) parent; + return pos; + #endif } } \ No newline at end of file diff --git a/dynarray.h b/dynarray.h index 29cb3f57..21c00dc6 100644 --- a/dynarray.h +++ b/dynarray.h @@ -220,11 +220,11 @@ class dynarray //! Equivalent to `erase(first, end())`, but potentially faster and does not require assignable T void erase_to_end(iterator first) noexcept; - void clear() noexcept { erase_to_end(begin()); } + void clear() noexcept { erase_to_end(begin()); } - bool empty() const noexcept { return _m.data == _m.end; } + [[nodiscard]] bool empty() const noexcept { return _m.data == _m.end; } - size_type size() const noexcept { return _m.end - _m.data; } + size_type size() const noexcept { return _m.end - _m.data; } void reserve(size_type minCap) { @@ -243,28 +243,28 @@ class dynarray allocator_type get_allocator() const noexcept { return _m; } - iterator begin() noexcept OEL_ALWAYS_INLINE { return _makeIter(_m.data); } - const_iterator begin() const noexcept OEL_ALWAYS_INLINE { return _makeIter(_m.data); } + iterator begin() noexcept { return _detail::MakeDynarrIter (_m, _m.data); } + const_iterator begin() const noexcept { return _detail::MakeDynarrIter(_m, _m.data); } const_iterator cbegin() const noexcept OEL_ALWAYS_INLINE { return begin(); } - iterator end() noexcept OEL_ALWAYS_INLINE { return _makeIter(_m.end); } - const_iterator end() const noexcept OEL_ALWAYS_INLINE { return _makeIter(_m.end); } + iterator end() noexcept { return _detail::MakeDynarrIter (_m, _m.end); } + const_iterator end() const noexcept { return _detail::MakeDynarrIter(_m, _m.end); } const_iterator cend() const noexcept OEL_ALWAYS_INLINE { return end(); } - reverse_iterator rbegin() noexcept OEL_ALWAYS_INLINE { return reverse_iterator{end()}; } + reverse_iterator rbegin() noexcept OEL_ALWAYS_INLINE { return reverse_iterator{end()}; } const_reverse_iterator rbegin() const noexcept OEL_ALWAYS_INLINE { return const_reverse_iterator{end()}; } - reverse_iterator rend() noexcept OEL_ALWAYS_INLINE { return reverse_iterator{begin()}; } + reverse_iterator rend() noexcept OEL_ALWAYS_INLINE { return reverse_iterator{begin()}; } const_reverse_iterator rend() const noexcept OEL_ALWAYS_INLINE { return const_reverse_iterator{begin()}; } T * data() noexcept OEL_ALWAYS_INLINE { return _m.data; } const T * data() const noexcept OEL_ALWAYS_INLINE { return _m.data; } - reference front() noexcept { return *begin(); } - const_reference front() const noexcept { return *begin(); } + reference front() noexcept { return (*this)[0]; } + const_reference front() const noexcept { return (*this)[0]; } - reference back() noexcept { return *_makeIter(_m.end - 1); } - const_reference back() const noexcept { return *_makeIter(_m.end - 1); } + reference back() noexcept { return *_detail::MakeDynarrIter (_m, _m.end - 1); } + const_reference back() const noexcept { return *_detail::MakeDynarrIter(_m, _m.end - 1); } reference at(size_type index); const_reference at(size_type index) const; @@ -367,17 +367,6 @@ class dynarray } - template< typename Ptr > - OEL_ALWAYS_INLINE auto _makeIter(Ptr pos) const noexcept - { - #if OEL_MEM_BOUND_DEBUG_LVL - return _detail::MakeDynarrayIter(pos, _m.data, this); - #else - return pos; - #endif - } - - void _moveInternBase(_internBase & src) noexcept { static_cast<_internBase &>(_m) = src; @@ -541,7 +530,7 @@ class dynarray if (newEnd < _m.end) { // downsizing, assign new and destroy rest src = copy(std::move(src), _m.data, newEnd); - erase_to_end(_makeIter(newEnd)); + erase_to_end(_detail::MakeDynarrIter(_m, newEnd)); } else // assign to old elements as far as we can { src = copy(std::move(src), _m.data, _m.end); @@ -693,7 +682,7 @@ typename dynarray::iterator { pPos = _insertRealloc< _emplaceHelper, _detail::ForwardT... > (pPos, static_cast(args)...); } - return _makeIter(pPos); + return _detail::MakeDynarrIter(_m, pPos); } template< typename T, typename Alloc > @@ -749,7 +738,7 @@ typename dynarray::iterator else { pPos = _insertRealloc<_insertRHelper>(pPos, std::move(first), count); } - return _makeIter(pPos); + return _detail::MakeDynarrIter(_m, pPos); } template< typename T, typename Alloc > diff --git a/unit_test/dynarray_other_gtest.cpp b/unit_test/dynarray_other_gtest.cpp index 3a3f64ec..2ab196e0 100644 --- a/unit_test/dynarray_other_gtest.cpp +++ b/unit_test/dynarray_other_gtest.cpp @@ -52,6 +52,21 @@ namespace static_assert(!oel::allocator_can_realloc< oel::allocator >); } +void testCompileDynarrayMembers() +{ + dynarray const d{0}; + dynarray::allocate_size_overhead(); + d.get_allocator(); + d.cbegin(); + d.cend(); + d.rbegin(); + d.rend(); + d.data(); + d.front(); + d.back(); + d.at(0); +} + TEST(dynarrayOtherTest, zeroBitRepresentation) { {