123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- //
- // based on boost.json
- //
- // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
- // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
- // Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net)
- //
- // 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 BOOST_COBALT_DETAIL_MONOTONIC_BUFFER_RESOURCE_HPP
- #define BOOST_COBALT_DETAIL_MONOTONIC_BUFFER_RESOURCE_HPP
- #include <boost/cobalt/config.hpp>
- #include <new>
- namespace boost::cobalt::detail
- {
- struct monotonic_resource
- {
- private:
- struct block_
- {
- void* p;
- std::size_t avail;
- std::size_t size;
- std::align_val_t aligned;
- block_* next;
- };
- block_ buffer_;
- block_* head_ = &buffer_;
- std::size_t chunk_size_{buffer_.size};
- public:
- constexpr monotonic_resource(void * buffer, std::size_t size)
- : buffer_{buffer, size, size, std::align_val_t{0u}, nullptr} {}
- constexpr monotonic_resource(std::size_t chunk_size = 1024)
- : buffer_{nullptr, 0u, 0u, std::align_val_t{0u}, nullptr}, chunk_size_(chunk_size) {}
- monotonic_resource(monotonic_resource && lhs) noexcept = delete;
- constexpr ~monotonic_resource()
- {
- if (head_ != &buffer_)
- release();
- }
- constexpr void release()
- {
- head_ = &buffer_;
- auto nx = buffer_.next;
- head_->next = nullptr;
- head_->avail = head_->size;
- while (nx != nullptr)
- {
- auto p = nx;
- nx = nx->next;
- #if defined(__cpp_sized_deallocation)
- const auto size = sizeof(block_) + p->size;
- operator delete(p->p, size, p->aligned);
- #else
- operator delete(p->p, p->aligned);
- #endif
- }
- }
- constexpr void * allocate(std::size_t size, std::align_val_t align_ = std::align_val_t(alignof(std::max_align_t)))
- {
- const auto align = (std::max)(static_cast<std::size_t>(align_), alignof(block_));
- // let's say size = 11, and align is 8, that leaves us with 3
- {
- const auto align_offset = size % align ;
- // padding is 5
- const auto padding = align - align_offset;
- const auto needed_size = size + padding;
- if (needed_size <= head_->avail) // fits, but we need to check alignment too
- {
- const auto offset = head_->size - head_->avail;
- auto pp = static_cast<char*>(head_->p) + offset + padding;
- head_->avail -= needed_size;
- return pp; // done
- }
- }
- // alright, we need to alloc something.
- const auto mem_size = (std::max)(chunk_size_, size);
- // add padding at the end
- const auto offset = (mem_size % alignof(block_));
- const auto padding = offset == 0 ? 0u : (alignof(block_) - offset);
- // size to allocate
- const auto raw_size = mem_size + padding;
- const auto alloc_size = raw_size + sizeof(block_);
- const auto aligned = std::align_val_t(align);
- const auto mem = ::operator new(alloc_size, aligned);
- const auto block_location = static_cast<char*>(mem) + mem_size + offset;
- head_ = head_->next = new (block_location) block_{mem, raw_size - size, raw_size, aligned, nullptr};
- return mem;
- }
- };
- template<typename T>
- struct monotonic_allocator
- {
- template<typename U>
- monotonic_allocator(monotonic_allocator<U> alloc) : resource_(alloc.resource_)
- {
- }
- using value_type = T;
- using size_type = std::size_t;
- using difference_type = std::ptrdiff_t;
- using propagate_on_container_move_assignment = std::true_type;
- [[nodiscard]] constexpr T* allocate( std::size_t n )
- {
- if (resource_)
- return static_cast<T*>(
- resource_->allocate(
- sizeof(T) * n,
- std::align_val_t(alignof(T))));
- else
- return std::allocator<T>().allocate(n);
- }
- constexpr void deallocate( T* p, std::size_t n )
- {
- if (!resource_)
- std::allocator<T>().deallocate(p, n);
- }
- monotonic_allocator(monotonic_resource * resource = nullptr) : resource_(resource) {}
- private:
- template<typename>
- friend struct monotonic_allocator;
- monotonic_resource * resource_{nullptr};
- };
- }
- #endif //BOOST_COBALT_DETAIL_MONOTONIC_BUFFER_RESOURCE_HPP
|