diff --git a/examples/chapter11_07a/src/util/STL/impl/allocator_impl.h b/examples/chapter11_07a/src/util/STL/impl/allocator_impl.h index ac7e8c742..838bc9794 100644 --- a/examples/chapter11_07a/src/util/STL/impl/allocator_impl.h +++ b/examples/chapter11_07a/src/util/STL/impl/allocator_impl.h @@ -1,12 +1,12 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2013. +// Copyright Christopher Kormanyos 2007 - 2026. // 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) // -#ifndef ALLOCATOR_IMPL_2010_02_23_H_ - #define ALLOCATOR_IMPL_2010_02_23_H_ +#ifndef ALLOCATOR_IMPL_2010_02_23_H + #define ALLOCATOR_IMPL_2010_02_23_H #include #include @@ -16,7 +16,7 @@ namespace std { template - inline void destroy_range(iterator_type first, iterator_type last, allocator_type a) + inline void destroy_range(iterator_type first, iterator_type last, allocator_type& a) { while(first != last) { @@ -27,12 +27,15 @@ } template - inline void deallocate_range(iterator_type first, iterator_type last, allocator_type a) + inline void deallocate_range(iterator_type first, iterator_type last, allocator_type& a) { - const std::size_t count = static_cast(std::distance(first, last)); + if(first != last) + { + const std::size_t count = static_cast(std::distance(first, last)); - a.deallocate(first, count); + a.deallocate(first, count); + } } } -#endif // ALLOCATOR_IMPL_2010_02_23_H_ +#endif // ALLOCATOR_IMPL_2010_02_23_H diff --git a/examples/chapter11_07a/src/util/STL/vector b/examples/chapter11_07a/src/util/STL/vector index 854830094..e1608ff5f 100644 --- a/examples/chapter11_07a/src/util/STL/vector +++ b/examples/chapter11_07a/src/util/STL/vector @@ -111,18 +111,18 @@ range_construct(first, last, typename std::iterator_traits::iterator_category()); } - vector(const vector& other) : my_allocator(other.my_allocator), - my_first(allocate_storage(my_allocator, other.size())), - my_last (end_pointer(my_first, other.size())), - my_end (my_last) + vector(const vector& other) : my_allocator(other.my_allocator), + my_first(allocate_storage(my_allocator, other.size())), + my_last (end_pointer(my_first, other.size())), + my_end (my_last) { copy_construct(other.my_first, other.my_last, my_first); } vector(const vector& other, const allocator_type& a) : my_allocator(a), - my_first(allocate_storage(my_allocator, other.size())), - my_last (end_pointer(my_first, other.size())), - my_end (my_last) + my_first(allocate_storage(my_allocator, other.size())), + my_last (end_pointer(my_first, other.size())), + my_end (my_last) { copy_construct(other.my_first, other.my_last, my_first); } @@ -138,9 +138,9 @@ } vector(vector&& other, const allocator_type& a) : my_allocator(a), - my_first(nullptr), - my_last (nullptr), - my_end (nullptr) + my_first(nullptr), + my_last (nullptr), + my_end (nullptr) { if(my_allocator == other.my_allocator) { @@ -164,7 +164,7 @@ const allocator_type& a = allocator_type()) : my_allocator(a), my_first(allocate_storage(my_allocator, lst.size())), my_last (end_pointer(my_first, lst.size())), - my_end (my_last) + my_end (my_last) { copy_construct(lst.begin(), lst.end(), my_first); } @@ -332,8 +332,9 @@ template void assign(input_iterator first, input_iterator last) { - clear(); - for(; first != last; ++first) { push_back(*first); } + assign_range(first, + last, + typename std::iterator_traits::iterator_category()); } void push_back(const value_type& value) @@ -474,6 +475,31 @@ } } + template + void assign_range(input_iterator first, + input_iterator last, + std::input_iterator_tag) + { + clear(); + for(; first != last; ++first) { push_back(*first); } + } + + template + void assign_range(forward_iterator first, + forward_iterator last, + std::forward_iterator_tag) + { + const size_type count = static_cast(std::distance(first, last)); + + clear(); + reserve(count); + + for(; first != last; ++first) + { + push_back(*first); + } + } + template void range_construct(input_iterator first, input_iterator last, @@ -501,7 +527,6 @@ construct(destination, *first); } } - }; template diff --git a/ref_app/src/util/STL/impl/allocator_impl.h b/ref_app/src/util/STL/impl/allocator_impl.h index fdfba793b..40c04b7b7 100644 --- a/ref_app/src/util/STL/impl/allocator_impl.h +++ b/ref_app/src/util/STL/impl/allocator_impl.h @@ -1,12 +1,12 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2013. +// Copyright Christopher Kormanyos 2007 - 2026. // 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) // -#ifndef ALLOCATOR_IMPL_2010_02_23_H_ - #define ALLOCATOR_IMPL_2010_02_23_H_ +#ifndef ALLOCATOR_IMPL_2010_02_23_H + #define ALLOCATOR_IMPL_2010_02_23_H #include #include @@ -16,7 +16,7 @@ namespace std { template - inline void destroy_range(iterator_type first, iterator_type last, allocator_type a) + inline void destroy_range(iterator_type first, iterator_type last, allocator_type& a) { while(first != last) { @@ -27,12 +27,15 @@ } template - inline void deallocate_range(iterator_type first, iterator_type last, allocator_type a) + inline void deallocate_range(iterator_type first, iterator_type last, allocator_type& a) { - const std::size_t count = static_cast(std::distance(first, last)); + if(first != last) + { + const std::size_t count = static_cast(std::distance(first, last)); - a.deallocate(first, count); + a.deallocate(first, count); + } } } -#endif // ALLOCATOR_IMPL_2010_02_23_H_ +#endif // ALLOCATOR_IMPL_2010_02_23_H diff --git a/ref_app/src/util/STL/vector b/ref_app/src/util/STL/vector index 02206946b..38fe1d5d1 100644 --- a/ref_app/src/util/STL/vector +++ b/ref_app/src/util/STL/vector @@ -111,18 +111,18 @@ range_construct(first, last, typename std::iterator_traits::iterator_category()); } - vector(const vector& other) : my_allocator(other.my_allocator), - my_first(allocate_storage(my_allocator, other.size())), - my_last (end_pointer(my_first, other.size())), - my_end (my_last) + vector(const vector& other) : my_allocator(other.my_allocator), + my_first(allocate_storage(my_allocator, other.size())), + my_last (end_pointer(my_first, other.size())), + my_end (my_last) { copy_construct(other.my_first, other.my_last, my_first); } vector(const vector& other, const allocator_type& a) : my_allocator(a), - my_first(allocate_storage(my_allocator, other.size())), - my_last (end_pointer(my_first, other.size())), - my_end (my_last) + my_first(allocate_storage(my_allocator, other.size())), + my_last (end_pointer(my_first, other.size())), + my_end (my_last) { copy_construct(other.my_first, other.my_last, my_first); } @@ -138,9 +138,9 @@ } vector(vector&& other, const allocator_type& a) : my_allocator(a), - my_first(nullptr), - my_last (nullptr), - my_end (nullptr) + my_first(nullptr), + my_last (nullptr), + my_end (nullptr) { if(my_allocator == other.my_allocator) { @@ -164,7 +164,7 @@ const allocator_type& a = allocator_type()) : my_allocator(a), my_first(allocate_storage(my_allocator, lst.size())), my_last (end_pointer(my_first, lst.size())), - my_end (my_last) + my_end (my_last) { copy_construct(lst.begin(), lst.end(), my_first); } @@ -332,8 +332,9 @@ template void assign(input_iterator first, input_iterator last) { - clear(); - for(; first != last; ++first) { push_back(*first); } + assign_range(first, + last, + typename std::iterator_traits::iterator_category()); } void push_back(const value_type& value) @@ -474,6 +475,31 @@ } } + template + void assign_range(input_iterator first, + input_iterator last, + std::input_iterator_tag) + { + clear(); + for(; first != last; ++first) { push_back(*first); } + } + + template + void assign_range(forward_iterator first, + forward_iterator last, + std::forward_iterator_tag) + { + const size_type count = static_cast(std::distance(first, last)); + + clear(); + reserve(count); + + for(; first != last; ++first) + { + push_back(*first); + } + } + template void range_construct(input_iterator first, input_iterator last, @@ -501,7 +527,6 @@ construct(destination, *first); } } - }; template diff --git a/ref_app/src/util/memory/util_ring_allocator.h b/ref_app/src/util/memory/util_ring_allocator.h index ef30988c3..451d36c20 100644 --- a/ref_app/src/util/memory/util_ring_allocator.h +++ b/ref_app/src/util/memory/util_ring_allocator.h @@ -18,110 +18,135 @@ { template - struct ring_arena { - static_assert(ArenaSize != 0U, "The ring arena must not be empty."); - static_assert(BufferAlignment != 0U && - (BufferAlignment & (BufferAlignment - 1U)) == 0U, - "The ring arena alignment must be a power of two."); - - alignas(BufferAlignment) std::array buffer{}; - - std::size_t head{}; - // Diagnostic count only. It does not describe live storage after wrap. - std::size_t allocated_bytes{}; - std::size_t peak_outstanding{}; - std::size_t allocations{}; - - // A rebound allocator must use the same storage as its original type. - static ring_arena instance; + struct ring_arena + { + static_assert(ArenaSize != 0U, "The ring arena must not be empty."); + + static_assert((BufferAlignment != 0U) && ((BufferAlignment & (BufferAlignment - 1U)) == 0U), + "The ring arena alignment must be a power of two."); + + alignas(BufferAlignment) std::array buffer { }; + + std::size_t head { }; + + // Diagnostic count only. It does not describe live storage after wrap. + std::size_t allocated_bytes { }; + std::size_t peak_outstanding { }; + std::size_t allocations { }; + + // A rebound allocator must use the same storage as its original type. + static ring_arena instance; }; template - ring_arena ring_arena::instance; + ring_arena ring_arena::instance { }; // Access must be externally serialized. This allocator is not interrupt- or // thread-safe, and it does not provide its own critical section. template - class ring_allocator { + class ring_allocator + { public: - using value_type = T; - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; - - static_assert(alignof(T) <= BufferAlignment, - "The ring allocator buffer is insufficiently aligned for T"); - - ring_allocator() noexcept = default; - - template - ring_allocator(const ring_allocator&) noexcept {} - - template - struct rebind { - using other = ring_allocator; - }; - - auto allocate(const std::size_t n) noexcept -> T* { - if (n > (std::numeric_limits::max)() / sizeof(T)) { - return nullptr; - } - - ring_arena* arena_ptr{ - &ring_arena::instance}; - - const std::size_t bytes = n * sizeof(T); - std::size_t at = arena_ptr->head; - const std::size_t remainder = at % alignof(T); - - if (remainder != 0U) { - at += alignof(T) - remainder; - } - - // This is an overwrite-style ring allocator: when the remaining - // tail is too small, start again at the beginning regardless of - // outstanding allocations. - if (at > arena_ptr->buffer.size() || - bytes > arena_ptr->buffer.size() - at) { - at = 0U; - if (bytes > arena_ptr->buffer.size()) { - return nullptr; - } - } - - arena_ptr->head = at + bytes; - arena_ptr->allocated_bytes += bytes; - arena_ptr->peak_outstanding = std::max(arena_ptr->peak_outstanding, - arena_ptr->allocated_bytes); - ++arena_ptr->allocations; - return reinterpret_cast(static_cast(arena_ptr->buffer.data() + at)); + using value_type = T; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + static_assert(alignof(T) <= BufferAlignment, + "The ring allocator buffer is insufficiently aligned for T"); + + ring_allocator() noexcept = default; + + template + ring_allocator(const ring_allocator&) noexcept { } + + template + struct rebind + { + using other = ring_allocator; + }; + + auto allocate(const std::size_t n) noexcept -> T* + { + if(n > (std::numeric_limits::max)() / sizeof(T)) + { + return nullptr; } - auto deallocate(T*, const std::size_t n) noexcept -> void { - ring_arena* arena_ptr{ - &ring_arena::instance}; + ring_arena* + arena_ptr + { + &ring_arena::instance + }; - if (n > (std::numeric_limits::max)() / sizeof(T)) { - return; - } + const std::size_t bytes = n * sizeof(T); + std::size_t at = arena_ptr->head; + const std::size_t remainder = at % alignof(T); - const std::size_t bytes = n * sizeof(T); - if (bytes <= arena_ptr->allocated_bytes) { - arena_ptr->allocated_bytes -= bytes; - } + if(remainder != 0U) + { + at += alignof(T) - remainder; } - static constexpr auto max_size() noexcept -> std::size_t { - return ArenaSize / sizeof(T); + // This is an overwrite-style ring allocator: when the remaining + // tail is too small, start again at the beginning regardless of + // outstanding allocations. + if(at > arena_ptr->buffer.size() || (bytes > (arena_ptr->buffer.size() - at))) + { + at = 0U; + + if(bytes > arena_ptr->buffer.size()) + { + return nullptr; + } } - private: - friend auto operator==(const ring_allocator&, const ring_allocator&) noexcept -> bool { - return true; } + arena_ptr->head = at + bytes; + arena_ptr->allocated_bytes += bytes; + arena_ptr->peak_outstanding = (std::max)(arena_ptr->peak_outstanding, arena_ptr->allocated_bytes); - friend auto operator!=(const ring_allocator&, const ring_allocator&) noexcept -> bool { - return false; } + ++arena_ptr->allocations; + + return static_cast(static_cast(arena_ptr->buffer.data() + at)); + } + + auto deallocate(T*, const std::size_t n) noexcept -> void + { + ring_arena* + arena_ptr + { + &ring_arena::instance + }; + + if(n > (std::numeric_limits::max)() / sizeof(T)) + { + return; + } + + const std::size_t bytes = n * sizeof(T); + + if(bytes <= arena_ptr->allocated_bytes) + { + arena_ptr->allocated_bytes -= bytes; + } + } + + static constexpr auto max_size() noexcept -> std::size_t + { + return ArenaSize / sizeof(T); + } + + private: + friend auto operator==(const ring_allocator&, const ring_allocator&) noexcept -> bool + { + return true; + } + + friend auto operator!=(const ring_allocator&, const ring_allocator&) noexcept -> bool + { + return false; + } }; }