File indexing completed on 2025-01-30 09:34:30
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef BOOST_COBALT_DETAIL_MONOTONIC_BUFFER_RESOURCE_HPP
0013 #define BOOST_COBALT_DETAIL_MONOTONIC_BUFFER_RESOURCE_HPP
0014
0015 #include <boost/cobalt/config.hpp>
0016 #include <new>
0017
0018 namespace boost::cobalt::detail
0019 {
0020
0021 struct monotonic_resource
0022 {
0023 private:
0024 struct block_
0025 {
0026 void* p;
0027 std::size_t avail;
0028 std::size_t size;
0029 std::align_val_t aligned;
0030 block_* next;
0031
0032 };
0033
0034 block_ buffer_;
0035 block_* head_ = &buffer_;
0036 std::size_t chunk_size_{buffer_.size};
0037 public:
0038 constexpr monotonic_resource(void * buffer, std::size_t size)
0039 : buffer_{buffer, size, size, std::align_val_t{0u}, nullptr} {}
0040
0041 constexpr monotonic_resource(std::size_t chunk_size = 1024)
0042 : buffer_{nullptr, 0u, 0u, std::align_val_t{0u}, nullptr}, chunk_size_(chunk_size) {}
0043
0044
0045 monotonic_resource(monotonic_resource && lhs) noexcept = delete;
0046 constexpr ~monotonic_resource()
0047 {
0048 if (head_ != &buffer_)
0049 release();
0050 }
0051 constexpr void release()
0052 {
0053 head_ = &buffer_;
0054 auto nx = buffer_.next;
0055 head_->next = nullptr;
0056 head_->avail = head_->size;
0057 while (nx != nullptr)
0058 {
0059 auto p = nx;
0060 nx = nx->next;
0061 #if defined(__cpp_sized_deallocation)
0062 const auto size = sizeof(block_) + p->size;
0063 operator delete(p->p, size, p->aligned);
0064 #else
0065 operator delete(p->p, p->aligned);
0066 #endif
0067 }
0068 }
0069
0070 constexpr void * allocate(std::size_t size, std::align_val_t align_ = std::align_val_t(alignof(std::max_align_t)))
0071 {
0072 const auto align = (std::max)(static_cast<std::size_t>(align_), alignof(block_));
0073
0074 {
0075 const auto align_offset = size % align ;
0076
0077 const auto padding = align - align_offset;
0078 const auto needed_size = size + padding;
0079 if (needed_size <= head_->avail)
0080 {
0081 const auto offset = head_->size - head_->avail;
0082 auto pp = static_cast<char*>(head_->p) + offset + padding;
0083 head_->avail -= needed_size;
0084 return pp;
0085 }
0086 }
0087
0088
0089 const auto mem_size = (std::max)(chunk_size_, size);
0090
0091 const auto offset = (mem_size % alignof(block_));
0092 const auto padding = offset == 0 ? 0u : (alignof(block_) - offset);
0093
0094 const auto raw_size = mem_size + padding;
0095 const auto alloc_size = raw_size + sizeof(block_);
0096
0097 const auto aligned = std::align_val_t(align);
0098 const auto mem = ::operator new(alloc_size, aligned);
0099 const auto block_location = static_cast<char*>(mem) + mem_size + offset;
0100 head_ = head_->next = new (block_location) block_{mem, raw_size - size, raw_size, aligned, nullptr};
0101
0102 return mem;
0103 }
0104
0105 };
0106
0107 template<typename T>
0108 struct monotonic_allocator
0109 {
0110 template<typename U>
0111 monotonic_allocator(monotonic_allocator<U> alloc) : resource_(alloc.resource_)
0112 {
0113
0114 }
0115 using value_type = T;
0116 using size_type = std::size_t;
0117 using difference_type = std::ptrdiff_t;
0118 using propagate_on_container_move_assignment = std::true_type;
0119
0120 [[nodiscard]] constexpr T* allocate( std::size_t n )
0121 {
0122 if (resource_)
0123 return static_cast<T*>(
0124 resource_->allocate(
0125 sizeof(T) * n,
0126 std::align_val_t(alignof(T))));
0127 else
0128 return std::allocator<T>().allocate(n);
0129 }
0130
0131 constexpr void deallocate( T* p, std::size_t n )
0132 {
0133 if (!resource_)
0134 std::allocator<T>().deallocate(p, n);
0135 }
0136 monotonic_allocator(monotonic_resource * resource = nullptr) : resource_(resource) {}
0137 private:
0138 template<typename>
0139 friend struct monotonic_allocator;
0140
0141 monotonic_resource * resource_{nullptr};
0142 };
0143
0144 }
0145
0146 #endif