Warning, file /include/Gaudi/Arena/Monotonic.h was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #pragma once
0012
0013 #include <Gaudi/Allocator/Arena.h>
0014 #include <GaudiKernel/Kernel.h>
0015 #include <boost/container/small_vector.hpp>
0016 #include <cstddef>
0017 #include <gsl/span>
0018 #include <numeric>
0019 #include <utility>
0020
0021 namespace Gaudi::Arena {
0022 namespace details {
0023 template <std::size_t Alignment>
0024 constexpr std::size_t align_up( std::size_t n ) {
0025 return ( n + ( Alignment - 1 ) ) & ~( Alignment - 1 );
0026 }
0027 }
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045 template <std::size_t Alignment = alignof( std::max_align_t ), typename UpstreamAllocator = std::allocator<std::byte>>
0046 class Monotonic {
0047
0048 static_assert( std::is_empty_v<UpstreamAllocator>, "Stateful upstream allocators are not yet supported." );
0049
0050
0051 std::size_t m_next_block_size{};
0052
0053
0054 std::size_t m_allocations{ 0 };
0055
0056
0057 std::byte* m_current{ nullptr };
0058
0059
0060 std::byte* m_current_end{ nullptr };
0061
0062
0063 boost::container::small_vector<gsl::span<std::byte>, 1> m_all_blocks;
0064
0065
0066 static constexpr std::size_t growth_factor = 2;
0067
0068 public:
0069 static constexpr std::size_t alignment = Alignment;
0070
0071
0072
0073
0074 Monotonic( std::size_t next_block_size ) noexcept
0075 : m_next_block_size{ details::align_up<Alignment>( next_block_size ) } {}
0076
0077 ~Monotonic() noexcept {
0078 for ( auto block : m_all_blocks ) { UpstreamAllocator{}.deallocate( block.data(), block.size() ); }
0079 }
0080
0081
0082
0083 Monotonic( Monotonic&& ) = delete;
0084 Monotonic( Monotonic const& ) = delete;
0085 Monotonic& operator=( Monotonic&& ) = delete;
0086 Monotonic& operator=( Monotonic const& ) = delete;
0087
0088
0089
0090
0091 template <std::size_t ReqAlign>
0092 std::byte* allocate( std::size_t n ) {
0093
0094
0095
0096 static_assert( ReqAlign <= alignment, "Requested alignment too large for this Gaudi::Arena::Monotonic!" );
0097
0098 std::size_t const aligned_n = details::align_up<Alignment>( n );
0099
0100 if ( !m_current || m_current + aligned_n > m_current_end ) {
0101
0102 auto next_block_size = std::max( m_next_block_size, aligned_n );
0103
0104 m_next_block_size = details::align_up<Alignment>( growth_factor * next_block_size );
0105
0106 m_current = UpstreamAllocator{}.allocate( next_block_size );
0107 m_current_end = m_current + next_block_size;
0108
0109 m_all_blocks.emplace_back( m_current, next_block_size );
0110 }
0111 m_allocations++;
0112 return std::exchange( m_current, m_current + aligned_n );
0113 }
0114
0115
0116
0117 constexpr void deallocate( std::byte*, std::size_t ) noexcept {}
0118
0119
0120
0121
0122
0123
0124
0125
0126 void reset() noexcept {
0127 m_allocations = 0;
0128 if ( !m_all_blocks.empty() ) {
0129
0130 if ( m_all_blocks.size() > 1 ) {
0131 for ( std::size_t i = 1; i < m_all_blocks.size(); ++i ) {
0132 UpstreamAllocator{}.deallocate( m_all_blocks[i].data(), m_all_blocks[i].size() );
0133 }
0134 m_all_blocks.resize( 1 );
0135 }
0136 auto reused_block = m_all_blocks.front();
0137 m_current = reused_block.data();
0138 m_current_end = m_current + reused_block.size();
0139 m_next_block_size = details::align_up<Alignment>( growth_factor * reused_block.size() );
0140 }
0141 }
0142
0143
0144
0145 [[nodiscard]] std::size_t capacity() const noexcept {
0146 return std::accumulate( m_all_blocks.begin(), m_all_blocks.end(), 0ul,
0147 []( std::size_t sum, auto block ) { return sum + block.size(); } );
0148 }
0149
0150
0151
0152 [[nodiscard]] std::size_t size() const noexcept { return capacity() - ( m_current_end - m_current ); }
0153
0154
0155
0156 [[nodiscard]] std::size_t num_blocks() const noexcept { return m_all_blocks.size(); }
0157
0158
0159
0160 [[nodiscard]] std::size_t num_allocations() const noexcept { return m_allocations; }
0161 };
0162 }
0163
0164 namespace Gaudi::Allocator {
0165
0166
0167
0168 template <typename T, typename DefaultResource = void, std::size_t Alignment = alignof( std::max_align_t ),
0169 typename UpstreamAllocator = std::allocator<std::byte>>
0170 using MonotonicArena =
0171 ::Gaudi::Allocator::Arena<::Gaudi::Arena::Monotonic<Alignment, UpstreamAllocator>, T, DefaultResource>;
0172 }