123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- //
- // 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_SBO_BUFFER_RESOURCE_HPP
- #define BOOST_COBALT_DETAIL_SBO_BUFFER_RESOURCE_HPP
- #include <boost/cobalt/config.hpp>
- namespace boost::cobalt::detail
- {
- struct sbo_resource
- #if !defined(BOOST_COBALT_NO_PMR)
- final : pmr::memory_resource
- #endif
- {
- private:
- struct block_
- {
- void* p{nullptr};
- std::size_t avail{0u};
- std::size_t size{0u};
- bool fragmented{false};
- };
- block_ buffer_;
- #if !defined(BOOST_COBALT_NO_PMR)
- pmr::memory_resource * upstream_;
- #endif
- constexpr std::size_t align_as_max_(std::size_t size)
- {
- auto diff = size % alignof(std::max_align_t );
- if (diff > 0)
- return size + alignof(std::max_align_t) - diff;
- else
- return size;
- }
- constexpr void align_as_max_()
- {
- const auto buffer = static_cast<char*>(buffer_.p) - static_cast<char*>(nullptr);
- const auto diff = buffer % alignof(std::max_align_t );
- if (diff > 0)
- {
- const auto padding = alignof(std::max_align_t) - diff;
- buffer_.p = static_cast<void*>(static_cast<char*>(nullptr) + buffer + padding);
- if (padding >= buffer_.size) [[unlikely]]
- {
- buffer_.size = 0;
- buffer_.avail = 0;
- }
- else
- {
- buffer_.size -= padding;
- buffer_.avail -= padding;
- }
- }
- }
- public:
- constexpr sbo_resource(void * buffer, std::size_t size
- #if !defined(BOOST_COBALT_NO_PMR)
- , pmr::memory_resource * upstream = pmr::get_default_resource()
- #endif
- ) : buffer_{buffer, size, size, false}
- #if !defined(BOOST_COBALT_NO_PMR)
- , upstream_(upstream)
- #endif
- {
- align_as_max_();
- }
- #if defined(BOOST_COBALT_NO_PMR)
- constexpr sbo_resource() : buffer_{nullptr, 0u, 0u, false} {}
- #else
- constexpr sbo_resource(pmr::memory_resource * upstream = pmr::get_default_resource())
- : buffer_{nullptr, 0u, 0u, false}, upstream_(upstream) {}
- #endif
- ~sbo_resource() = default;
- constexpr void * do_allocate(std::size_t size, std::size_t align)
- #if !defined(BOOST_COBALT_NO_PMR)
- override
- #endif
- {
- const auto sz = align_as_max_(size);
- if (sz <= buffer_.avail && !buffer_.fragmented) [[likely]]
- {
- auto p = static_cast<char*>(buffer_.p) + buffer_.size - buffer_.avail;
- buffer_.avail -= sz;
- return p;
- }
- else
- #if !defined(BOOST_COBALT_NO_PMR)
- return upstream_->allocate(size, align);
- #else
- return operator new(size, std::align_val_t(align));
- #endif
- }
- constexpr void do_deallocate(void * p, std::size_t size, std::size_t align)
- #if !defined(BOOST_COBALT_NO_PMR)
- override
- #endif
- {
- auto begin = static_cast<char*>(static_cast<char*>(buffer_.p));
- auto end = begin + buffer_.size;
- auto itr = static_cast<char*>(p);
- if(begin <= itr && itr < end) [[likely]]
- {
- const auto sz = align_as_max_(size);
- const auto used_mem_end = end - buffer_.avail;
- const auto dealloc_end = itr + sz;
- if (used_mem_end != dealloc_end )
- buffer_.fragmented = true;
- buffer_.avail += sz;
- if (buffer_.avail == buffer_.size)
- buffer_.fragmented = false;
- }
- else
- {
- #if !defined(BOOST_COBALT_NO_PMR)
- upstream_->deallocate(p, size, align);
- #else
- #if defined(__cpp_sized_deallocation)
- operator delete(p, size, std::align_val_t(align));
- #else
- operator delete(p, std::align_val_t(align));
- #endif
- #endif
- }
- }
- #if !defined(BOOST_COBALT_NO_PMR)
- constexpr bool do_is_equal(memory_resource const& other) const noexcept override
- {
- return this == &other;
- }
- #endif
- };
- inline sbo_resource * get_null_sbo_resource()
- {
- static sbo_resource empty_resource;
- return &empty_resource;
- }
- template<typename T>
- struct sbo_allocator
- {
- template<typename U>
- sbo_allocator(sbo_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 )
- {
- BOOST_ASSERT(resource_);
- return static_cast<T*>(resource_->do_allocate(sizeof(T) * n, alignof(T)));
- }
- constexpr void deallocate( T* p, std::size_t n )
- {
- BOOST_ASSERT(resource_);
- resource_->do_deallocate(p, sizeof(T) * n, alignof(T));
- }
- sbo_allocator(sbo_resource * resource) : resource_(resource) {}
- private:
- template<typename>
- friend struct sbo_allocator;
- sbo_resource * resource_{nullptr};
- };
- }
- #endif //BOOST_COBALT_DETAIL_SBO_BUFFER_RESOURCE_HPP
|