Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-17 08:39:19

0001 //
0002 // Copyright (c) 2025 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_IO_BUFFER_HPP
0009 #define BOOST_COBALT_IO_BUFFER_HPP
0010 
0011 #include <boost/asio/buffer.hpp>
0012 #include <boost/asio/registered_buffer.hpp>
0013 #include <boost/cobalt/config.hpp>
0014 #include <span>
0015 
0016 namespace boost::cobalt::io
0017 {
0018 
0019 using asio::buffer;
0020 using asio::mutable_buffer;
0021 
0022 
0023 struct mutable_buffer_sequence
0024 {
0025   std::size_t buffer_count() const {return tail_.size() + 1u;}
0026 
0027 #if defined(BOOST_ASIO_HAS_IO_URING)
0028   mutable_buffer_sequence(asio::mutable_registered_buffer buffer = {}) : registered_(buffer) { }
0029   mutable_buffer_sequence(asio::mutable_buffer head)  : registered_{}
0030   {
0031     this->head_ = head;
0032   }
0033   mutable_buffer_sequence(const mutable_buffer_sequence & rhs) : registered_(rhs.registered_), tail_(rhs.tail_) {}
0034 #else
0035   mutable_buffer_sequence(asio::mutable_registered_buffer buffer = {}) : head_(buffer.buffer()) { }
0036   mutable_buffer_sequence(asio::mutable_buffer head)  : head_{head} { }
0037   mutable_buffer_sequence(const mutable_buffer_sequence & rhs) : head_(rhs.head_), tail_(rhs.tail_) {}
0038 #endif
0039 
0040   mutable_buffer_sequence& operator=(const mutable_buffer_sequence & rhs)
0041   {
0042 #if defined(BOOST_ASIO_HAS_IO_URING)
0043     registered_ = rhs.registered_;
0044 #else
0045     head_ = rhs.head_;
0046 #endif
0047     tail_ = rhs.tail_;
0048     return *this;
0049   }
0050   ~mutable_buffer_sequence() {}
0051 
0052   template<typename T>
0053     requires (std::constructible_from<std::span<const asio::mutable_buffer>, const T&>)
0054   mutable_buffer_sequence(const T & value)
0055 #if defined(BOOST_ASIO_HAS_IO_URING)
0056         : registered_{}
0057 #endif
0058   {
0059     std::span<const asio::mutable_buffer> spn(value);
0060     if (!spn.empty())
0061     {
0062       head_ = spn.front();
0063       tail_ = spn.subspan(1u);
0064     }
0065   }
0066 
0067   mutable_buffer_sequence(std::span<const asio::mutable_buffer> spn)
0068 #if defined(BOOST_ASIO_HAS_IO_URING)
0069         : registered_{}
0070 #endif
0071   {
0072     if (!spn.empty())
0073     {
0074       head_ = spn.front();
0075       tail_ = spn.subspan(1u);
0076     }
0077   }
0078 
0079   mutable_buffer_sequence & operator+=(std::size_t n)
0080   {
0081     if (n < head_.size())
0082       head_ += n;
0083     else
0084     {
0085       n -= head_.size();
0086       std::size_t idx = 0u;
0087       while (idx < tail_.size() && n > tail_[idx].size() )
0088         n -= tail_[idx++].size();
0089 
0090       if (idx == tail_.size()) // we're exceeding the size, so just drop everything
0091       {
0092         tail_ = {};
0093         head_ = {};
0094       }
0095       if (tail_.empty())
0096         head_ = {};
0097       else
0098       {
0099         head_ = tail_[idx];
0100         head_ += n;
0101         tail_ = tail_.subspan(idx + 1);
0102       }
0103     }
0104     return *this;
0105   }
0106 
0107   struct const_iterator
0108   {
0109     using iterator_category = std::random_access_iterator_tag;
0110     using value_type        = asio::mutable_buffer;
0111     using difference_type   = std::ptrdiff_t;
0112     using pointer           = const asio::mutable_buffer*;
0113     using reference         = const asio::mutable_buffer&;
0114 
0115     BOOST_COBALT_MSVC_NOINLINE
0116     const_iterator(asio::mutable_buffer head,
0117                    std::span<const asio::mutable_buffer> tail,
0118                    std::size_t offset = std::numeric_limits<std::size_t>::max()) : head_(head), tail_(tail), offset_(offset) {}
0119 
0120     BOOST_COBALT_MSVC_NOINLINE
0121     reference & operator*() const
0122     {
0123       return offset_ == std::numeric_limits<std::size_t>::max() ? head_ : tail_[offset_];
0124     }
0125 
0126     BOOST_COBALT_MSVC_NOINLINE
0127     pointer operator->() const
0128     {
0129       return offset_ == std::numeric_limits<std::size_t>::max() ? &head_ : &tail_[offset_];
0130     }
0131 
0132     const_iterator operator++()
0133     {
0134       offset_++;
0135       return *this;
0136     }
0137 
0138     const_iterator operator++(int)
0139     {
0140       auto o = *this;
0141       offset_ ++ ;
0142       return o;
0143     }
0144 
0145     const_iterator operator--()
0146     {
0147       offset_ --;
0148       return *this;
0149     }
0150 
0151     const_iterator operator--(int)
0152     {
0153       auto o = *this;
0154       offset_ -- ;
0155       return o;
0156     }
0157 
0158     const_iterator operator+(difference_type diff) const
0159     {
0160       auto res = *this;
0161       res.offset_ += diff;
0162       return res;
0163     }
0164 
0165     const_iterator operator-(difference_type diff) const
0166     {
0167       auto res = *this;
0168       res.offset_ -= diff;
0169       return res;
0170     }
0171 
0172     const_iterator& operator+=(difference_type diff)
0173     {
0174       offset_ += diff;
0175       return *this;
0176     }
0177 
0178     const_iterator operator-=(difference_type diff)
0179     {
0180       offset_ -= diff;
0181       return *this;
0182     }
0183 
0184     reference operator[](difference_type n) const
0185     {
0186       auto idx = offset_ + n;
0187       return idx == std::numeric_limits<std::size_t>::max() ? head_ : tail_[idx];
0188     }
0189 
0190     difference_type operator-(const_iterator itr) const
0191     {
0192       return static_cast<difference_type>(offset_) - static_cast<difference_type>(itr.offset_);
0193     }
0194 
0195     friend auto operator<=>(const const_iterator & lhs, const const_iterator & rhs)
0196     {
0197       return std::make_tuple(lhs.head_.data(), lhs.head_.size(), lhs.tail_.data(), lhs.tail_.size(), lhs.offset_)
0198          <=> std::make_tuple(rhs.head_.data(), rhs.head_.size(), rhs.tail_.data(), rhs.tail_.size(), rhs.offset_);
0199     };
0200 
0201     friend bool operator==(const const_iterator & lhs, const const_iterator & rhs)
0202     {
0203       return std::make_tuple(lhs.head_.data(), lhs.head_.size(), lhs.tail_.data(), lhs.tail_.size(), lhs.offset_)
0204           == std::make_tuple(rhs.head_.data(), rhs.head_.size(), rhs.tail_.data(), rhs.tail_.size(), rhs.offset_);
0205     }
0206 
0207     friend bool operator!=(const const_iterator & lhs, const const_iterator & rhs)
0208     {
0209       return std::make_tuple(lhs.head_.data(), lhs.head_.size(), lhs.tail_.data(), lhs.tail_.size(), lhs.offset_)
0210           != std::make_tuple(rhs.head_.data(), rhs.head_.size(), rhs.tail_.data(), rhs.tail_.size(), rhs.offset_);
0211     }
0212    private:
0213 
0214     asio::mutable_buffer head_;
0215     std::span<const asio::mutable_buffer> tail_;
0216 
0217     std::size_t offset_{std::numeric_limits<std::size_t>::max()};
0218   };
0219 
0220   BOOST_COBALT_MSVC_NOINLINE
0221   const_iterator begin() const {return const_iterator{head_, tail_};}
0222   BOOST_COBALT_MSVC_NOINLINE
0223   const_iterator   end() const {return const_iterator{head_, tail_, tail_.size()};}
0224 
0225   bool is_registered() const
0226   {
0227 #if defined(BOOST_ASIO_HAS_IO_URING)
0228     return registered_.id() != asio::registered_buffer_id();
0229 #else
0230     return false;
0231 #endif
0232   }
0233 
0234   template<typename Func>
0235   friend auto visit(const mutable_buffer_sequence & seq, Func && func)
0236   {
0237     if (seq.buffer_count() > 1u)
0238       return std::forward<Func>(func)(seq);
0239 #if defined(BOOST_ASIO_HAS_IO_URING)
0240     else if (seq.is_registered())
0241       return std::forward<Func>(func)(seq.registered_);
0242 #endif
0243     else
0244       return std::forward<Func>(func)(seq.head_);
0245   }
0246  private:
0247 #if defined(BOOST_ASIO_HAS_IO_URING)
0248   union {
0249     asio::mutable_registered_buffer registered_{};
0250     asio::mutable_buffer head_;
0251   };
0252 #else
0253 
0254   asio::mutable_buffer head_;
0255 #endif
0256   std::span<const asio::mutable_buffer> tail_;
0257 };
0258 
0259 
0260 using asio::const_buffer;
0261 
0262 struct const_buffer_sequence
0263 {
0264   std::size_t buffer_count() const {return tail_.size() + 1u;}
0265 
0266 #if defined(BOOST_ASIO_HAS_IO_URING)
0267   const_buffer_sequence(asio::const_registered_buffer buffer = {}) : registered_(buffer) {}
0268   const_buffer_sequence(asio::mutable_registered_buffer buffer)    : registered_(buffer) {}
0269   const_buffer_sequence(asio::const_buffer head)   : registered_{} { this->head_ = head; }
0270   const_buffer_sequence(asio::mutable_buffer head) : registered_{} { this->head_ = head; }
0271   const_buffer_sequence(const const_buffer_sequence & rhs) : registered_(rhs.registered_), tail_(rhs.tail_) {}
0272 #else
0273 
0274   const_buffer_sequence(asio::const_registered_buffer buffer = {}) : head_(buffer.buffer()) {}
0275   const_buffer_sequence(asio::mutable_registered_buffer buffer)    : head_(buffer.buffer()) {}
0276   const_buffer_sequence(asio::const_buffer head)   : head_{ head} { }
0277   const_buffer_sequence(asio::mutable_buffer head) : head_{ head} { }
0278   const_buffer_sequence(const const_buffer_sequence & rhs) : head_(rhs.head_), tail_(rhs.tail_) {}
0279 #endif
0280   template<typename T>
0281     requires (std::constructible_from<std::span<const asio::const_buffer>, const T&>)
0282   const_buffer_sequence(const T & value)
0283 #if defined(BOOST_ASIO_HAS_IO_URING)
0284       : registered_{}
0285 #endif
0286   {
0287     std::span<const asio::const_buffer> spn(value);
0288     if (!spn.empty())
0289     {
0290       head_ = spn.front();
0291       tail_ = spn.subspan(1u);
0292     }
0293   }
0294 
0295   const_buffer_sequence& operator=(const const_buffer_sequence & rhs)
0296   {
0297 #if defined(BOOST_ASIO_HAS_IO_URING)
0298     registered_ = rhs.registered_;
0299 #else
0300     head_ = rhs.head_;
0301 #endif
0302     tail_ = rhs.tail_;
0303     return *this;
0304   }
0305   ~const_buffer_sequence() {}
0306 
0307   const_buffer_sequence(std::span<const asio::const_buffer> spn)
0308 #if defined(BOOST_ASIO_HAS_IO_URING)
0309     : registered_{}
0310 #endif
0311   {
0312     if (!spn.empty())
0313     {
0314       head_ = spn.front();
0315       tail_ = spn.subspan(1u);
0316     }
0317   }
0318 
0319   const_buffer_sequence & operator+=(std::size_t n)
0320   {
0321     if (n < head_.size())
0322       head_ += n;
0323     else
0324     {
0325       n -= head_.size();
0326       std::size_t idx = 0u;
0327       while (idx < tail_.size() && n > tail_[idx].size() )
0328         n -= tail_[idx++].size();
0329 
0330       if (idx == tail_.size()) // we're exceeding the size, so just drop everything
0331       {
0332         tail_ = {};
0333         head_ = {};
0334       }
0335       if (tail_.empty())
0336         head_ = {};
0337       else
0338       {
0339         head_ = tail_[idx];
0340         head_ += n;
0341         tail_ = tail_.subspan(idx + 1);
0342       }
0343     }
0344     return *this;
0345   }
0346 
0347   struct const_iterator
0348   {
0349     using iterator_category = std::random_access_iterator_tag;
0350     using value_type        = asio::const_buffer;
0351     using difference_type   = std::ptrdiff_t;
0352     using pointer           = const asio::const_buffer*;
0353     using reference         = const asio::const_buffer&;
0354 
0355     BOOST_COBALT_MSVC_NOINLINE
0356     const_iterator(asio::const_buffer head,
0357                    std::span<const asio::const_buffer> tail,
0358                    std::size_t offset = std::numeric_limits<std::size_t>::max()) : head_(head), tail_(tail), offset_(offset)
0359     {
0360 
0361     }
0362 
0363     BOOST_COBALT_MSVC_NOINLINE
0364     reference & operator*() const
0365     {
0366       return offset_ == std::numeric_limits<std::size_t>::max() ? head_ : tail_[offset_];
0367     }
0368 
0369     BOOST_COBALT_MSVC_NOINLINE
0370     pointer operator->() const
0371     {
0372       return offset_ == std::numeric_limits<std::size_t>::max() ? &head_ : &tail_[offset_];
0373     }
0374 
0375     const_iterator operator++()
0376     {
0377       offset_++;
0378       return *this;
0379     }
0380 
0381     const_iterator operator++(int)
0382     {
0383       auto o = *this;
0384       offset_ ++ ;
0385       return o;
0386     }
0387 
0388     const_iterator operator--()
0389     {
0390       offset_ --;
0391       return *this;
0392     }
0393 
0394     const_iterator operator--(int)
0395     {
0396       auto o = *this;
0397       offset_ -- ;
0398       return o;
0399     }
0400 
0401     const_iterator operator+(difference_type diff) const
0402     {
0403       auto res = *this;
0404       res.offset_ += diff;
0405       return res;
0406     }
0407 
0408     const_iterator operator-(difference_type diff) const
0409     {
0410       auto res = *this;
0411       res.offset_ -= diff;
0412       return res;
0413     }
0414 
0415     const_iterator& operator+=(difference_type diff)
0416     {
0417       offset_ += diff;
0418       return *this;
0419     }
0420 
0421     const_iterator operator-=(difference_type diff)
0422     {
0423       offset_ -= diff;
0424       return *this;
0425     }
0426 
0427     BOOST_COBALT_MSVC_NOINLINE
0428     reference operator[](difference_type n) const
0429     {
0430       auto idx = offset_ + n;
0431       return idx == std::numeric_limits<std::size_t>::max() ? head_ : tail_[idx];
0432     }
0433 
0434     difference_type operator-(const_iterator itr) const
0435     {
0436       return static_cast<difference_type>(offset_) - static_cast<difference_type>(itr.offset_);
0437     }
0438 
0439     friend auto operator<=>(const const_iterator & lhs, const const_iterator & rhs)
0440     {
0441       return std::make_tuple(lhs.head_.data(), lhs.head_.size(), lhs.tail_.data(), lhs.tail_.size(), lhs.offset_)
0442              <=> std::make_tuple(rhs.head_.data(), rhs.head_.size(), rhs.tail_.data(), rhs.tail_.size(), rhs.offset_);
0443     };
0444     friend bool operator==(const const_iterator & lhs, const const_iterator & rhs)
0445     {
0446       return std::make_tuple(lhs.head_.data(), lhs.head_.size(), lhs.tail_.data(), lhs.tail_.size(), lhs.offset_)
0447           == std::make_tuple(rhs.head_.data(), rhs.head_.size(), rhs.tail_.data(), rhs.tail_.size(), rhs.offset_);
0448     }
0449     friend bool operator!=(const const_iterator & lhs, const const_iterator & rhs)
0450     {
0451       return std::make_tuple(lhs.head_.data(), lhs.head_.size(), lhs.tail_.data(), lhs.tail_.size(), lhs.offset_)
0452           != std::make_tuple(rhs.head_.data(), rhs.head_.size(), rhs.tail_.data(), rhs.tail_.size(), rhs.offset_);
0453     }
0454 
0455    private:
0456 
0457     asio::const_buffer head_;
0458     std::span<const asio::const_buffer> tail_;
0459 
0460     std::size_t offset_{std::numeric_limits<std::size_t>::max()};
0461 
0462   };
0463 
0464   BOOST_COBALT_MSVC_NOINLINE
0465   const_iterator begin() const {return const_iterator{head_, tail_};}
0466 
0467   BOOST_COBALT_MSVC_NOINLINE
0468   const_iterator   end() const {return const_iterator{head_, tail_, tail_.size()};}
0469 
0470   bool is_registered() const
0471   {
0472 #if defined(BOOST_ASIO_HAS_IO_URING)
0473     return registered_.id() != asio::registered_buffer_id();
0474 #else
0475     return false;
0476 #endif
0477   }
0478 
0479   template<typename Func>
0480   friend auto visit(const const_buffer_sequence & seq, Func && func)
0481   {
0482     if (seq.buffer_count() > 1u)
0483       return std::forward<Func>(func)(seq);
0484     // Windows doesn't support registerd buffers anyhow
0485 #if defined(BOOST_ASIO_HAS_IO_URING)
0486     else if (seq.is_registered())
0487       return std::forward<Func>(func)(seq.registered_);
0488 #endif
0489     else
0490       return std::forward<Func>(func)(seq.head_);
0491   }
0492 
0493  private:
0494 #if defined(BOOST_ASIO_HAS_IO_URING)
0495   union {
0496     asio::const_registered_buffer registered_;
0497     asio::const_buffer head_;
0498   };
0499 #else
0500   asio::const_buffer head_;
0501 #endif
0502   std::span<const asio::const_buffer> tail_;
0503 };
0504 
0505 using asio::buffer_copy;
0506 using asio::buffer_size;
0507 
0508 }
0509 
0510 #endif //BOOST_COBALT_IO_BUFFER_HPP