Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:44:25

0001 //
0002 // Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 
0008 #ifndef BOOST_COBALT_DETAIL_SBO_BUFFER_RESOURCE_HPP
0009 #define BOOST_COBALT_DETAIL_SBO_BUFFER_RESOURCE_HPP
0010 
0011 #include <boost/cobalt/config.hpp>
0012 
0013 namespace boost::cobalt::detail
0014 {
0015 
0016 struct sbo_resource
0017 #if !defined(BOOST_COBALT_NO_PMR)
0018   final : pmr::memory_resource
0019 #endif
0020 {
0021  private:
0022   struct block_
0023   {
0024     void* p{nullptr};
0025     std::size_t avail{0u};
0026     std::size_t size{0u};
0027     bool fragmented{false};
0028   };
0029 
0030   block_ buffer_;
0031 #if !defined(BOOST_COBALT_NO_PMR)
0032   pmr::memory_resource * upstream_;
0033 #endif
0034   constexpr std::size_t align_as_max_(std::size_t size)
0035   {
0036     auto diff = size % alignof(std::max_align_t );
0037     if (diff > 0)
0038       return size + alignof(std::max_align_t) - diff;
0039     else
0040       return size;
0041   }
0042   constexpr void align_as_max_()
0043   {
0044     const auto buffer = static_cast<char*>(buffer_.p) - static_cast<char*>(nullptr);
0045     const auto diff = buffer % alignof(std::max_align_t );
0046     if (diff > 0)
0047     {
0048       const auto padding = alignof(std::max_align_t) - diff;
0049       buffer_.p = static_cast<void*>(static_cast<char*>(nullptr) + buffer + padding);
0050       if (padding >= buffer_.size) [[unlikely]]
0051       {
0052         buffer_.size = 0;
0053         buffer_.avail = 0;
0054       }
0055       else
0056       {
0057         buffer_.size -= padding;
0058         buffer_.avail -= padding;
0059       }
0060 
0061     }
0062   }
0063 
0064  public:
0065   constexpr sbo_resource(void * buffer, std::size_t size
0066 #if !defined(BOOST_COBALT_NO_PMR)
0067                         , pmr::memory_resource * upstream = pmr::get_default_resource()
0068 #endif
0069       ) : buffer_{buffer, size, size, false}
0070 #if !defined(BOOST_COBALT_NO_PMR)
0071       , upstream_(upstream)
0072 #endif
0073   {
0074     align_as_max_();
0075   }
0076 
0077 #if defined(BOOST_COBALT_NO_PMR)
0078   constexpr sbo_resource() : buffer_{nullptr, 0u, 0u, false} {}
0079 
0080 #else
0081   constexpr sbo_resource(pmr::memory_resource * upstream = pmr::get_default_resource())
0082       : buffer_{nullptr, 0u, 0u, false}, upstream_(upstream) {}
0083 #endif
0084 
0085   ~sbo_resource() = default;
0086 
0087   constexpr void * do_allocate(std::size_t size, std::size_t align)
0088 #if !defined(BOOST_COBALT_NO_PMR)
0089   override
0090 #endif
0091   {
0092     const auto sz = align_as_max_(size);
0093     if (sz <= buffer_.avail && !buffer_.fragmented) [[likely]]
0094     {
0095       auto p = static_cast<char*>(buffer_.p) + buffer_.size - buffer_.avail;
0096       buffer_.avail -= sz;
0097       return p;
0098     }
0099     else
0100 #if !defined(BOOST_COBALT_NO_PMR)
0101       return upstream_->allocate(size, align);
0102 #else
0103       return operator new(size, std::align_val_t(align));
0104 #endif
0105 
0106   }
0107 
0108   constexpr void do_deallocate(void * p, std::size_t size, std::size_t align)
0109 #if !defined(BOOST_COBALT_NO_PMR)
0110       override
0111 #endif
0112   {
0113     auto begin = static_cast<char*>(static_cast<char*>(buffer_.p));
0114     auto end = begin + buffer_.size;
0115     auto itr = static_cast<char*>(p);
0116 
0117     if(begin <= itr && itr < end) [[likely]]
0118     {
0119       const auto sz = align_as_max_(size);
0120       const auto used_mem_end = end - buffer_.avail;
0121       const auto dealloc_end = itr + sz;
0122       if (used_mem_end != dealloc_end )
0123         buffer_.fragmented = true;
0124       buffer_.avail += sz;
0125       if (buffer_.avail == buffer_.size)
0126         buffer_.fragmented = false;
0127     }
0128     else
0129     {
0130 #if !defined(BOOST_COBALT_NO_PMR)
0131       upstream_->deallocate(p, size, align);
0132 #else
0133   #if defined(__cpp_sized_deallocation)
0134       operator delete(p, size, std::align_val_t(align));
0135   #else
0136       operator delete(p, std::align_val_t(align));
0137   #endif
0138 #endif
0139 
0140     }
0141   }
0142 
0143 #if defined(BOOST_COBALT_NO_PMR)
0144   [[nodiscard]]
0145     void*
0146     allocate(size_t bytes, size_t alignment = alignof(std::max_align_t))
0147     {
0148       return ::operator new(bytes, do_allocate(bytes, alignment));
0149     }
0150 
0151     void
0152     deallocate(void* p, size_t bytes, size_t alignment = alignof(std::max_align_t))
0153     {
0154       return do_deallocate(p, bytes, alignment);
0155     }
0156 #endif
0157 
0158 #if !defined(BOOST_COBALT_NO_PMR)
0159   constexpr bool do_is_equal(memory_resource const& other) const noexcept override
0160   {
0161     return this == &other;
0162   }
0163 #endif
0164 };
0165 
0166 inline sbo_resource * get_null_sbo_resource()
0167 {
0168   static sbo_resource empty_resource;
0169   return &empty_resource;
0170 }
0171 
0172 template<typename T>
0173 struct sbo_allocator
0174 {
0175   template<typename U>
0176   sbo_allocator(sbo_allocator<U> alloc) : resource_(alloc.resource_)
0177   {
0178 
0179   }
0180   using value_type                             = T;
0181   using size_type                              = std::size_t;
0182   using difference_type                        = std::ptrdiff_t;
0183   using propagate_on_container_move_assignment = std::true_type;
0184 
0185   [[nodiscard]] constexpr T* allocate( std::size_t n )
0186   {
0187     BOOST_ASSERT(resource_);
0188     return static_cast<T*>(resource_->do_allocate(sizeof(T) * n, alignof(T)));
0189   }
0190 
0191   constexpr void deallocate( T* p, std::size_t n )
0192   {
0193     BOOST_ASSERT(resource_);
0194     resource_->do_deallocate(p, sizeof(T) * n, alignof(T));
0195   }
0196   sbo_allocator(sbo_resource * resource) : resource_(resource) {}
0197 
0198   sbo_resource * resource() const {return resource_;}
0199  private:
0200   template<typename>
0201   friend struct sbo_allocator;
0202 
0203   sbo_resource * resource_{nullptr};
0204 };
0205 
0206 }
0207 
0208 #endif //BOOST_COBALT_DETAIL_SBO_BUFFER_RESOURCE_HPP