Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:34:30

0001 //
0002 // based on boost.json
0003 //
0004 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
0005 // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
0006 // Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net)
0007 //
0008 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0009 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
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     // let's say size = 11, and align is 8, that leaves us with 3
0074     {
0075       const auto align_offset = size % align ;
0076       // padding is 5
0077       const auto padding = align  - align_offset;
0078       const auto needed_size = size + padding;
0079       if (needed_size <= head_->avail) // fits, but we need to check alignment too
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; // done
0085       }
0086     }
0087 
0088     // alright, we need to alloc something.
0089     const auto mem_size = (std::max)(chunk_size_, size);
0090     // add padding at the end
0091     const auto offset = (mem_size % alignof(block_));
0092     const auto padding = offset == 0 ? 0u : (alignof(block_) - offset);
0093     // size to allocate
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 //BOOST_COBALT_DETAIL_MONOTONIC_BUFFER_RESOURCE_HPP