| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511 |
- //
- // Copyright (c) 2025 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_IO_BUFFER_HPP
- #define BOOST_COBALT_IO_BUFFER_HPP
- #include <boost/asio/buffer.hpp>
- #include <boost/asio/registered_buffer.hpp>
- #include <boost/cobalt/config.hpp>
- #include <span>
- namespace boost::cobalt::io
- {
- using asio::buffer;
- using asio::mutable_buffer;
- struct mutable_buffer_sequence
- {
- std::size_t buffer_count() const {return tail_.size() + 1u;}
- #if defined(BOOST_ASIO_HAS_IO_URING)
- mutable_buffer_sequence(asio::mutable_registered_buffer buffer = {}) : registered_(buffer) { }
- mutable_buffer_sequence(asio::mutable_buffer head) : registered_{}
- {
- this->head_ = head;
- }
- mutable_buffer_sequence(const mutable_buffer_sequence & rhs) : registered_(rhs.registered_), tail_(rhs.tail_) {}
- #else
- mutable_buffer_sequence(asio::mutable_registered_buffer buffer = {}) : head_(buffer.buffer()) { }
- mutable_buffer_sequence(asio::mutable_buffer head) : head_{head} { }
- mutable_buffer_sequence(const mutable_buffer_sequence & rhs) : head_(rhs.head_), tail_(rhs.tail_) {}
- #endif
- mutable_buffer_sequence& operator=(const mutable_buffer_sequence & rhs)
- {
- #if defined(BOOST_ASIO_HAS_IO_URING)
- registered_ = rhs.registered_;
- #else
- head_ = rhs.head_;
- #endif
- tail_ = rhs.tail_;
- return *this;
- }
- ~mutable_buffer_sequence() {}
- template<typename T>
- requires (std::constructible_from<std::span<const asio::mutable_buffer>, const T&>)
- mutable_buffer_sequence(const T & value)
- #if defined(BOOST_ASIO_HAS_IO_URING)
- : registered_{}
- #endif
- {
- std::span<const asio::mutable_buffer> spn(value);
- if (!spn.empty())
- {
- head_ = spn.front();
- tail_ = spn.subspan(1u);
- }
- }
- mutable_buffer_sequence(std::span<const asio::mutable_buffer> spn)
- #if defined(BOOST_ASIO_HAS_IO_URING)
- : registered_{}
- #endif
- {
- if (!spn.empty())
- {
- head_ = spn.front();
- tail_ = spn.subspan(1u);
- }
- }
- mutable_buffer_sequence & operator+=(std::size_t n)
- {
- if (n < head_.size())
- head_ += n;
- else
- {
- n -= head_.size();
- std::size_t idx = 0u;
- while (idx < tail_.size() && n > tail_[idx].size() )
- n -= tail_[idx++].size();
- if (idx == tail_.size()) // we're exceeding the size, so just drop everything
- {
- tail_ = {};
- head_ = {};
- }
- if (tail_.empty())
- head_ = {};
- else
- {
- head_ = tail_[idx];
- head_ += n;
- tail_ = tail_.subspan(idx + 1);
- }
- }
- return *this;
- }
- struct const_iterator
- {
- using iterator_category = std::random_access_iterator_tag;
- using value_type = asio::mutable_buffer;
- using difference_type = std::ptrdiff_t;
- using pointer = const asio::mutable_buffer*;
- using reference = const asio::mutable_buffer&;
- BOOST_COBALT_MSVC_NOINLINE
- const_iterator(asio::mutable_buffer head,
- std::span<const asio::mutable_buffer> tail,
- std::size_t offset = std::numeric_limits<std::size_t>::max()) : head_(head), tail_(tail), offset_(offset) {}
- BOOST_COBALT_MSVC_NOINLINE
- reference & operator*() const
- {
- return offset_ == std::numeric_limits<std::size_t>::max() ? head_ : tail_[offset_];
- }
- BOOST_COBALT_MSVC_NOINLINE
- pointer operator->() const
- {
- return offset_ == std::numeric_limits<std::size_t>::max() ? &head_ : &tail_[offset_];
- }
- const_iterator operator++()
- {
- offset_++;
- return *this;
- }
- const_iterator operator++(int)
- {
- auto o = *this;
- offset_ ++ ;
- return o;
- }
- const_iterator operator--()
- {
- offset_ --;
- return *this;
- }
- const_iterator operator--(int)
- {
- auto o = *this;
- offset_ -- ;
- return o;
- }
- const_iterator operator+(difference_type diff) const
- {
- auto res = *this;
- res.offset_ += diff;
- return res;
- }
- const_iterator operator-(difference_type diff) const
- {
- auto res = *this;
- res.offset_ -= diff;
- return res;
- }
- const_iterator& operator+=(difference_type diff)
- {
- offset_ += diff;
- return *this;
- }
- const_iterator operator-=(difference_type diff)
- {
- offset_ -= diff;
- return *this;
- }
- reference operator[](difference_type n) const
- {
- auto idx = offset_ + n;
- return idx == std::numeric_limits<std::size_t>::max() ? head_ : tail_[idx];
- }
- difference_type operator-(const_iterator itr) const
- {
- return static_cast<difference_type>(offset_) - static_cast<difference_type>(itr.offset_);
- }
- friend auto operator<=>(const const_iterator & lhs, const const_iterator & rhs)
- {
- return std::make_tuple(lhs.head_.data(), lhs.head_.size(), lhs.tail_.data(), lhs.tail_.size(), lhs.offset_)
- <=> std::make_tuple(rhs.head_.data(), rhs.head_.size(), rhs.tail_.data(), rhs.tail_.size(), rhs.offset_);
- };
- friend bool operator==(const const_iterator & lhs, const const_iterator & rhs)
- {
- return std::make_tuple(lhs.head_.data(), lhs.head_.size(), lhs.tail_.data(), lhs.tail_.size(), lhs.offset_)
- == std::make_tuple(rhs.head_.data(), rhs.head_.size(), rhs.tail_.data(), rhs.tail_.size(), rhs.offset_);
- }
- friend bool operator!=(const const_iterator & lhs, const const_iterator & rhs)
- {
- return std::make_tuple(lhs.head_.data(), lhs.head_.size(), lhs.tail_.data(), lhs.tail_.size(), lhs.offset_)
- != std::make_tuple(rhs.head_.data(), rhs.head_.size(), rhs.tail_.data(), rhs.tail_.size(), rhs.offset_);
- }
- private:
- asio::mutable_buffer head_;
- std::span<const asio::mutable_buffer> tail_;
- std::size_t offset_{std::numeric_limits<std::size_t>::max()};
- };
- BOOST_COBALT_MSVC_NOINLINE
- const_iterator begin() const {return const_iterator{head_, tail_};}
- BOOST_COBALT_MSVC_NOINLINE
- const_iterator end() const {return const_iterator{head_, tail_, tail_.size()};}
- bool is_registered() const
- {
- #if defined(BOOST_ASIO_HAS_IO_URING)
- return registered_.id() != asio::registered_buffer_id();
- #else
- return false;
- #endif
- }
- template<typename Func>
- friend auto visit(const mutable_buffer_sequence & seq, Func && func)
- {
- if (seq.buffer_count() > 1u)
- return std::forward<Func>(func)(seq);
- #if defined(BOOST_ASIO_HAS_IO_URING)
- else if (seq.is_registered())
- return std::forward<Func>(func)(seq.registered_);
- #endif
- else
- return std::forward<Func>(func)(seq.head_);
- }
- private:
- #if defined(BOOST_ASIO_HAS_IO_URING)
- union {
- asio::mutable_registered_buffer registered_{};
- asio::mutable_buffer head_;
- };
- #else
- asio::mutable_buffer head_;
- #endif
- std::span<const asio::mutable_buffer> tail_;
- };
- using asio::const_buffer;
- struct const_buffer_sequence
- {
- std::size_t buffer_count() const {return tail_.size() + 1u;}
- #if defined(BOOST_ASIO_HAS_IO_URING)
- const_buffer_sequence(asio::const_registered_buffer buffer = {}) : registered_(buffer) {}
- const_buffer_sequence(asio::mutable_registered_buffer buffer) : registered_(buffer) {}
- const_buffer_sequence(asio::const_buffer head) : registered_{} { this->head_ = head; }
- const_buffer_sequence(asio::mutable_buffer head) : registered_{} { this->head_ = head; }
- const_buffer_sequence(const const_buffer_sequence & rhs) : registered_(rhs.registered_), tail_(rhs.tail_) {}
- #else
- const_buffer_sequence(asio::const_registered_buffer buffer = {}) : head_(buffer.buffer()) {}
- const_buffer_sequence(asio::mutable_registered_buffer buffer) : head_(buffer.buffer()) {}
- const_buffer_sequence(asio::const_buffer head) : head_{ head} { }
- const_buffer_sequence(asio::mutable_buffer head) : head_{ head} { }
- const_buffer_sequence(const const_buffer_sequence & rhs) : head_(rhs.head_), tail_(rhs.tail_) {}
- #endif
- template<typename T>
- requires (std::constructible_from<std::span<const asio::const_buffer>, const T&>)
- const_buffer_sequence(const T & value)
- #if defined(BOOST_ASIO_HAS_IO_URING)
- : registered_{}
- #endif
- {
- std::span<const asio::const_buffer> spn(value);
- if (!spn.empty())
- {
- head_ = spn.front();
- tail_ = spn.subspan(1u);
- }
- }
- const_buffer_sequence& operator=(const const_buffer_sequence & rhs)
- {
- #if defined(BOOST_ASIO_HAS_IO_URING)
- registered_ = rhs.registered_;
- #else
- head_ = rhs.head_;
- #endif
- tail_ = rhs.tail_;
- return *this;
- }
- ~const_buffer_sequence() {}
- const_buffer_sequence(std::span<const asio::const_buffer> spn)
- #if defined(BOOST_ASIO_HAS_IO_URING)
- : registered_{}
- #endif
- {
- if (!spn.empty())
- {
- head_ = spn.front();
- tail_ = spn.subspan(1u);
- }
- }
- const_buffer_sequence & operator+=(std::size_t n)
- {
- if (n < head_.size())
- head_ += n;
- else
- {
- n -= head_.size();
- std::size_t idx = 0u;
- while (idx < tail_.size() && n > tail_[idx].size() )
- n -= tail_[idx++].size();
- if (idx == tail_.size()) // we're exceeding the size, so just drop everything
- {
- tail_ = {};
- head_ = {};
- }
- if (tail_.empty())
- head_ = {};
- else
- {
- head_ = tail_[idx];
- head_ += n;
- tail_ = tail_.subspan(idx + 1);
- }
- }
- return *this;
- }
- struct const_iterator
- {
- using iterator_category = std::random_access_iterator_tag;
- using value_type = asio::const_buffer;
- using difference_type = std::ptrdiff_t;
- using pointer = const asio::const_buffer*;
- using reference = const asio::const_buffer&;
- BOOST_COBALT_MSVC_NOINLINE
- const_iterator(asio::const_buffer head,
- std::span<const asio::const_buffer> tail,
- std::size_t offset = std::numeric_limits<std::size_t>::max()) : head_(head), tail_(tail), offset_(offset)
- {
- }
- BOOST_COBALT_MSVC_NOINLINE
- reference & operator*() const
- {
- return offset_ == std::numeric_limits<std::size_t>::max() ? head_ : tail_[offset_];
- }
- BOOST_COBALT_MSVC_NOINLINE
- pointer operator->() const
- {
- return offset_ == std::numeric_limits<std::size_t>::max() ? &head_ : &tail_[offset_];
- }
- const_iterator operator++()
- {
- offset_++;
- return *this;
- }
- const_iterator operator++(int)
- {
- auto o = *this;
- offset_ ++ ;
- return o;
- }
- const_iterator operator--()
- {
- offset_ --;
- return *this;
- }
- const_iterator operator--(int)
- {
- auto o = *this;
- offset_ -- ;
- return o;
- }
- const_iterator operator+(difference_type diff) const
- {
- auto res = *this;
- res.offset_ += diff;
- return res;
- }
- const_iterator operator-(difference_type diff) const
- {
- auto res = *this;
- res.offset_ -= diff;
- return res;
- }
- const_iterator& operator+=(difference_type diff)
- {
- offset_ += diff;
- return *this;
- }
- const_iterator operator-=(difference_type diff)
- {
- offset_ -= diff;
- return *this;
- }
- BOOST_COBALT_MSVC_NOINLINE
- reference operator[](difference_type n) const
- {
- auto idx = offset_ + n;
- return idx == std::numeric_limits<std::size_t>::max() ? head_ : tail_[idx];
- }
- difference_type operator-(const_iterator itr) const
- {
- return static_cast<difference_type>(offset_) - static_cast<difference_type>(itr.offset_);
- }
- friend auto operator<=>(const const_iterator & lhs, const const_iterator & rhs)
- {
- return std::make_tuple(lhs.head_.data(), lhs.head_.size(), lhs.tail_.data(), lhs.tail_.size(), lhs.offset_)
- <=> std::make_tuple(rhs.head_.data(), rhs.head_.size(), rhs.tail_.data(), rhs.tail_.size(), rhs.offset_);
- };
- friend bool operator==(const const_iterator & lhs, const const_iterator & rhs)
- {
- return std::make_tuple(lhs.head_.data(), lhs.head_.size(), lhs.tail_.data(), lhs.tail_.size(), lhs.offset_)
- == std::make_tuple(rhs.head_.data(), rhs.head_.size(), rhs.tail_.data(), rhs.tail_.size(), rhs.offset_);
- }
- friend bool operator!=(const const_iterator & lhs, const const_iterator & rhs)
- {
- return std::make_tuple(lhs.head_.data(), lhs.head_.size(), lhs.tail_.data(), lhs.tail_.size(), lhs.offset_)
- != std::make_tuple(rhs.head_.data(), rhs.head_.size(), rhs.tail_.data(), rhs.tail_.size(), rhs.offset_);
- }
- private:
- asio::const_buffer head_;
- std::span<const asio::const_buffer> tail_;
- std::size_t offset_{std::numeric_limits<std::size_t>::max()};
- };
- BOOST_COBALT_MSVC_NOINLINE
- const_iterator begin() const {return const_iterator{head_, tail_};}
- BOOST_COBALT_MSVC_NOINLINE
- const_iterator end() const {return const_iterator{head_, tail_, tail_.size()};}
- bool is_registered() const
- {
- #if defined(BOOST_ASIO_HAS_IO_URING)
- return registered_.id() != asio::registered_buffer_id();
- #else
- return false;
- #endif
- }
- template<typename Func>
- friend auto visit(const const_buffer_sequence & seq, Func && func)
- {
- if (seq.buffer_count() > 1u)
- return std::forward<Func>(func)(seq);
- // Windows doesn't support registerd buffers anyhow
- #if defined(BOOST_ASIO_HAS_IO_URING)
- else if (seq.is_registered())
- return std::forward<Func>(func)(seq.registered_);
- #endif
- else
- return std::forward<Func>(func)(seq.head_);
- }
- private:
- #if defined(BOOST_ASIO_HAS_IO_URING)
- union {
- asio::const_registered_buffer registered_;
- asio::const_buffer head_;
- };
- #else
- asio::const_buffer head_;
- #endif
- std::span<const asio::const_buffer> tail_;
- };
- using asio::buffer_copy;
- using asio::buffer_size;
- }
- #endif //BOOST_COBALT_IO_BUFFER_HPP
|