File indexing completed on 2026-08-17 08:39:19
0001
0002
0003
0004
0005
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())
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())
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
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