MySQL 9.2.0
Source Code Documentation
buffer.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2019, 2024, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is designed to work with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have either included with
14 the program or referenced in the documentation.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24*/
25
26#ifndef MYSQL_HARNESS_NET_TS_BUFFER_H_
27#define MYSQL_HARNESS_NET_TS_BUFFER_H_
28
29#include <algorithm> // copy
30#include <array>
31#include <limits> // std::numeric_limits
32#include <span>
33#include <stdexcept> // length_error
34#include <string>
35#include <string_view>
36#include <system_error>
37#include <type_traits>
38#include <utility>
39#include <vector>
40
41#include "mysql/harness/net_ts/executor.h" // async_completion
44
45namespace net {
46
47// 16.3 [buffer.err]
48
49enum class stream_errc {
50 eof = 1,
52};
53} // namespace net
54
55namespace std {
56template <>
57struct is_error_code_enum<net::stream_errc> : public std::true_type {};
58} // namespace std
59
60namespace net {
61inline const std::error_category &stream_category() noexcept {
62 class stream_category_impl : public std::error_category {
63 public:
64 const char *name() const noexcept override { return "stream"; }
65 std::string message(int ev) const override {
66 switch (static_cast<stream_errc>(ev)) {
68 return "eof";
70 return "not found";
71 default:
72 return "unknown";
73 }
74 }
75
76 bool equivalent(int mycode,
77 const std::error_condition &other) const noexcept override {
78 if (*this == other.category() ||
79 std::string_view(name()) ==
80 std::string_view(other.category().name())) {
81 return mycode == other.value();
82 }
83
84 return false;
85 }
86
87 bool equivalent(const std::error_code &other,
88 int mycode) const noexcept override {
89 if (*this == other.category() ||
90 std::string_view(name()) ==
91 std::string_view(other.category().name())) {
92 return mycode == other.value();
93 }
94
95 return false;
96 }
97 };
98
99 static stream_category_impl instance;
100 return instance;
101}
102
103inline std::error_code make_error_code(net::stream_errc e) noexcept {
104 return {static_cast<int>(e), net::stream_category()};
105}
106
107inline std::error_condition make_error_condition(net::stream_errc e) noexcept {
108 return {static_cast<int>(e), net::stream_category()};
109}
110
111// 16.4 [buffer.mutable]
112
114 public:
115 mutable_buffer() noexcept : data_{nullptr}, size_{0} {}
116
117 mutable_buffer(void *p, size_t n) noexcept : data_{p}, size_{n} {}
118
119 void *data() const noexcept { return data_; }
120 size_t size() const noexcept { return size_; }
121
122 mutable_buffer &operator+=(size_t n) noexcept {
123 data_ = static_cast<char *>(data_) + std::min(n, size_);
124 size_ = size_ - std::min(n, size_);
125 return *this;
126 }
127
128 private:
129 void *data_;
130 size_t size_;
131};
132
133// 16.5 [buffer.const]
134
136 public:
137 const_buffer() noexcept : data_{nullptr}, size_{0} {}
138 const_buffer(const void *p, size_t n) noexcept : data_{p}, size_{n} {}
139 const_buffer(const mutable_buffer &b) noexcept
140 : data_{b.data()}, size_{b.size()} {}
141
142 const void *data() const noexcept { return data_; }
143 size_t size() const noexcept { return size_; }
144
145 const_buffer &operator+=(size_t n) noexcept {
146 const size_t inc_size = std::min(n, size_);
147 data_ = static_cast<const char *>(data_) + inc_size;
148 size_ -= inc_size;
149 return *this;
150 }
151
152 private:
153 const void *data_;
154 size_t size_;
155};
156
157// 16.6 [buffer.traits]
158
159template <class T>
161
162template <class T>
164
165template <class T>
167
168template <class T>
171
172template <class T>
173struct is_dynamic_buffer;
174
175template <class T>
177
178// 16.7 [buffer.seq.access]
179
181 const const_buffer &b) noexcept {
182 return std::addressof(b);
183}
184
185inline const const_buffer *buffer_sequence_end(const const_buffer &b) noexcept {
186 return std::addressof(b) + 1;
187}
188
189template <class C>
190inline auto buffer_sequence_begin(C &c) noexcept -> decltype(c.begin()) {
191 return c.begin();
192}
193
194template <class C>
195inline auto buffer_sequence_begin(const C &c) noexcept -> decltype(c.begin()) {
196 return c.begin();
197}
198
199template <class C>
200inline auto buffer_sequence_end(C &c) noexcept -> decltype(c.end()) {
201 return c.end();
202}
203
204template <class C>
205inline auto buffer_sequence_end(const C &c) noexcept -> decltype(c.end()) {
206 return c.end();
207}
208
210 const mutable_buffer &b) noexcept {
211 return std::addressof(b);
212}
213
215 const mutable_buffer &b) noexcept {
216 return std::addressof(b) + 1;
217}
218
219namespace impl {
220
221// const_buffer_sequence and mutable_buffer_sequence share the same
222// requirements, just with different expected BufferTypes
223template <class T, class BufferType,
224 class Begin = decltype(net::buffer_sequence_begin(
225 std::declval<typename std::add_lvalue_reference<T>::type>())),
226 class End = decltype(net::buffer_sequence_end(
227 std::declval<typename std::add_lvalue_reference<T>::type>()))>
228using buffer_sequence_requirements = std::bool_constant<std::conjunction_v<
229 // check if buffer_sequence_begin(T &) and buffer_sequence_end(T &)
230 // exist and return the same type
231 std::is_same<Begin, End>,
232 // check if ::value_type of the retval of buffer_sequence_begin() can be
233 // converted into a BufferType
234 std::is_convertible<typename std::iterator_traits<Begin>::value_type,
235 BufferType>>>;
236
237template <class T, class BufferType, class = void>
238struct is_buffer_sequence : std::false_type {};
239
240template <class T, class BufferType>
242 T, BufferType, std::void_t<buffer_sequence_requirements<T, BufferType>>>
244
245template <class T>
247 : is_buffer_sequence<T, net::const_buffer>::type {};
248
249template <class T>
251 : is_buffer_sequence<T, net::mutable_buffer>::type {};
252
253} // namespace impl
254
255template <class T>
257
258template <class T>
260
261namespace impl {
262template <class T, class = void>
263struct is_dynamic_buffer : std::false_type {};
264
265/*
266 * helper function for requirement checks.
267 *
268 * - function isn't implemented, just declared to type-check
269 * - function params are default initialized, never have to be specified
270 * - function params exist only to apply type-checks against them and pass them
271 * as parameter to decltype() like checks
272 */
273template <class T, class U = std::remove_const_t<T>>
274auto dynamic_buffer_requirements(U *__x = nullptr, const U *__const_x = nullptr,
275 size_t __n = 0)
276 -> std::enable_if_t<std::conjunction<
277 // is copy constructible
278 std::is_copy_constructible<U>,
279 // has a const_buffers_type that's a const_buffer_sequence
281 // has a mutable_buffers_type that's a mutable_buffer_sequence
283 // has 'size_t size() const' member
284 std::is_same<decltype(__const_x->size()), size_t>,
285 // has 'size_t max_size() const' member
286 std::is_same<decltype(__const_x->max_size()), size_t>,
287 // has 'size_t capacity() const' member
288 std::is_same<decltype(__const_x->capacity()), size_t>,
289 // has 'const_buffer_type data(size_t, size_t) const' member
290 std::is_same<decltype(__const_x->data(__n, __n)),
291 typename T::const_buffers_type>,
292 // has 'mutable_buffers_type data(size_t, size_t)' member
293 std::is_same<decltype(__x->data(__n, __n)),
294 typename T::mutable_buffers_type>,
295 // has 'void grow(size_t)' member
296 std::is_void<decltype(__x->grow(__n))>,
297 // has 'void shrink(size_t)' member
298 std::is_void<decltype(__x->shrink(__n))>,
299 // has 'void consume(size_t)' member
300 std::is_void<decltype(__x->consume(__n))>>::value>;
301
302template <class T>
304 : std::true_type {};
305} // namespace impl
306
307template <class T>
309
310// 16.8 [buffer.size]
311
312template <class ConstBufferSequence>
313inline size_t buffer_size(const ConstBufferSequence &buffers) noexcept {
314 size_t total_size{0};
315 auto end = buffer_sequence_end(buffers);
316
317 for (auto i = buffer_sequence_begin(buffers); i != end; ++i) {
318 const_buffer b(*i);
319
320 total_size += b.size();
321 }
322
323 return total_size;
324}
325
326template <>
327inline size_t buffer_size<const_buffer>(const const_buffer &b) noexcept {
328 return b.size();
329}
330
331template <>
332inline size_t buffer_size<mutable_buffer>(const mutable_buffer &b) noexcept {
333 return b.size();
334}
335
336/**
337 * copy bytes from a ConstBufferSequence to a MutableBufferSequence.
338 *
339 * copies min(max_bytes, buffer_size(src), buffer_size(dest)) bytes
340 *
341 * @param dest buffer-sequence to copy to
342 * @param src buffer-sequence to copy from
343 * @param max_size max bytes to copy
344 * @return bytes transferred from src to dest
345 *
346 * see: 16.9 [buffer.copy]
347 */
348template <class MutableBufferSequence, class ConstBufferSequence>
349size_t buffer_copy(const MutableBufferSequence &dest,
350 const ConstBufferSequence &src,
351 const size_t max_size) noexcept {
352 size_t transfered{0};
353 auto dest_cur = buffer_sequence_begin(dest);
354 auto const dest_end = buffer_sequence_end(dest);
355 auto src_cur = buffer_sequence_begin(src);
356 auto const src_end = buffer_sequence_end(src);
357
358 const_buffer src_buf;
359 mutable_buffer dest_buf;
360
361 while (transfered < max_size) {
362 // if buffer is empty, fetch the next one, if there is one
363 if (src_buf.size() == 0) {
364 if (src_cur == src_end) break;
365 src_buf = const_buffer(*src_cur++);
366 }
367 if (dest_buf.size() == 0) {
368 if (dest_cur == dest_end) break;
369 dest_buf = mutable_buffer(*dest_cur++);
370 }
371
372 size_t to_copy = std::min(dest_buf.size(), src_buf.size());
373 to_copy = std::min(to_copy, max_size - transfered);
374
375 // use std::copy() instead of std::memcpy() as it will be constexpr in C++20
376 // and results in the same code as a memcpy() already
377 std::copy(static_cast<const char *>(src_buf.data()),
378 std::next(static_cast<const char *>(src_buf.data()), to_copy),
379 static_cast<char *>(dest_buf.data()));
380
381 src_buf += to_copy;
382 dest_buf += to_copy;
383
384 transfered += to_copy;
385 }
386
387 return transfered;
388}
389
390template <class MutableBufferSequence, class ConstBufferSequence>
391size_t buffer_copy(const MutableBufferSequence &dest,
392 const ConstBufferSequence &src) noexcept {
393 return buffer_copy(dest, src, std::numeric_limits<size_t>::max());
394}
395
396// 16.10 [buffer.arithmetic]
397
398inline mutable_buffer operator+(const mutable_buffer &b, size_t n) noexcept {
399 const size_t inc_size = std::min(n, b.size());
400
401 return {static_cast<char *>(b.data()) + inc_size, b.size() - inc_size};
402}
403inline mutable_buffer operator+(size_t n, const mutable_buffer &b) noexcept {
404 return operator+(b, n);
405}
406
407inline const_buffer operator+(const const_buffer &b, size_t n) noexcept {
408 const size_t inc_size = std::min(n, b.size());
409 return {static_cast<const char *>(b.data()) + inc_size, b.size() - inc_size};
410}
411
412inline const_buffer operator+(size_t n, const const_buffer &b) noexcept {
413 return operator+(b, n);
414}
415
416// 16.11 [buffer.creation]
417
418inline mutable_buffer buffer(void *p, size_t n) noexcept { return {p, n}; }
419inline const_buffer buffer(const void *p, size_t n) noexcept { return {p, n}; }
420
421inline mutable_buffer buffer(const mutable_buffer &b) noexcept { return b; }
422inline mutable_buffer buffer(const mutable_buffer &b, size_t n) noexcept {
423 return {b.data(), std::min(b.size(), n)};
424}
425
426inline const_buffer buffer(const const_buffer &b) noexcept { return b; }
427inline const_buffer buffer(const const_buffer &b, size_t n) noexcept {
428 return {b.data(), std::min(b.size(), n)};
429}
430
431namespace impl {
432template <typename T>
433inline mutable_buffer to_mutable_buffer(T *data, size_t n) {
434 return {n ? data : nullptr, sizeof(*data) * n};
435}
436
437template <typename T>
438inline const_buffer to_const_buffer(const T *data, size_t n) {
439 return {n ? data : nullptr, sizeof(*data) * n};
440}
441} // namespace impl
442
443template <class T, size_t N>
444inline mutable_buffer buffer(T (&data)[N]) noexcept {
445 return impl::to_mutable_buffer(data, N);
446}
447
448template <class T, size_t N>
449inline const_buffer buffer(const T (&data)[N]) noexcept {
450 return impl::to_const_buffer(data, N);
451}
452
453template <class T, size_t N>
454inline mutable_buffer buffer(std::array<T, N> &data) noexcept {
455 return impl::to_mutable_buffer(data.data(), N);
456}
457
458template <class T, size_t N>
459inline const_buffer buffer(std::array<const T, N> &data) noexcept {
460 return impl::to_const_buffer(data.data(), N);
461}
462
463template <class T, size_t N>
464inline const_buffer buffer(const std::array<T, N> &data) noexcept {
465 return impl::to_const_buffer(data.data(), N);
466}
467
468template <class T, class Allocator>
469inline mutable_buffer buffer(std::vector<T, Allocator> &data) noexcept {
470 return impl::to_mutable_buffer(data.data(), data.size());
471}
472
473template <class T, class Allocator>
474inline const_buffer buffer(const std::vector<T, Allocator> &data) noexcept {
475 return impl::to_const_buffer(data.data(), data.size());
476}
477
478template <class CharT, class Traits, class Allocator>
480 std::basic_string<CharT, Traits, Allocator> &data) noexcept {
481 return data.empty() ? mutable_buffer{}
482 : impl::to_mutable_buffer(&data.front(), data.size());
483}
484
485template <class CharT, class Traits, class Allocator>
487 const std::basic_string<CharT, Traits, Allocator> &data) noexcept {
488 return data.empty() ? const_buffer{}
489 : impl::to_const_buffer(&data.front(), data.size());
490}
491
492template <class CharT, class Traits>
494 const std::basic_string_view<CharT, Traits> &data) noexcept {
495 return data.empty() ? const_buffer{}
496 : impl::to_const_buffer(data.data(), data.size());
497}
498
499template <class T, std::size_t E>
500inline const_buffer buffer(const std::span<T, E> &data) noexcept {
501 return data.empty() ? const_buffer{}
502 : impl::to_const_buffer(data.data(), data.size());
503}
504
505template <class T, size_t N>
506inline mutable_buffer buffer(T (&data)[N], size_t n) noexcept {
507 return buffer(buffer(data), n);
508}
509
510template <class T, size_t N>
511inline const_buffer buffer(const T (&data)[N], size_t n) noexcept {
512 return buffer(buffer(data), n);
513}
514
515template <class T, size_t N>
516inline mutable_buffer buffer(std::array<T, N> &data, size_t n) noexcept {
517 return buffer(buffer(data), n);
518}
519
520template <class T, size_t N>
521inline const_buffer buffer(std::array<const T, N> &data, size_t n) noexcept {
522 return buffer(buffer(data), n);
523}
524
525template <class T, size_t N>
526inline const_buffer buffer(const std::array<T, N> &data, size_t n) noexcept {
527 return buffer(buffer(data), n);
528}
529
530template <class T, class Allocator>
531inline mutable_buffer buffer(std::vector<T, Allocator> &data,
532 size_t n) noexcept {
533 return buffer(buffer(data), n);
534}
535
536template <class T, class Allocator>
537inline const_buffer buffer(const std::vector<T, Allocator> &data,
538 size_t n) noexcept {
539 return buffer(buffer(data), n);
540}
541
542template <class CharT, class Traits, class Allocator>
543inline mutable_buffer buffer(std::basic_string<CharT, Traits, Allocator> &data,
544 size_t n) noexcept {
545 return buffer(buffer(data), n);
546}
547
548template <class CharT, class Traits, class Allocator>
550 const std::basic_string<CharT, Traits, Allocator> &data,
551 size_t n) noexcept {
552 return buffer(buffer(data), n);
553}
554
555template <class T, std::size_t E>
556inline const_buffer buffer(const std::span<T, E> &data, size_t n) noexcept {
557 return buffer(buffer(data), n);
558}
559
560namespace impl {
561// base for net::dynamic_vector_buffer and net::dynamic_string_buffer who share
562// the same interface, just differ by storage type
563template <class T>
565 public:
568
569 explicit dynamic_buffer_base(T &v) noexcept
570 : v_{v}, max_size_{v.max_size()} {}
571 dynamic_buffer_base(T &v, size_t max_size) noexcept
572 : v_{v}, max_size_{max_size} {}
573
574 /**
575 * number of bytes.
576 */
577 size_t size() const noexcept { return std::min(v_.size(), max_size_); }
578
579 /**
580 * max number of bytes.
581 */
582 size_t max_size() const noexcept { return max_size_; }
583
584 /**
585 * max number of bytes without requiring reallocation.
586 */
587 size_t capacity() const noexcept {
588 return std::min(v_.capacity(), max_size_);
589 }
590
591 const_buffers_type data(size_t pos, size_t n) const noexcept {
592 return buffer(buffer(v_, max_size_) + pos, n);
593 }
594
595 mutable_buffers_type data(size_t pos, size_t n) {
596 return buffer(buffer(v_, max_size_) + pos, n);
597 }
598
599 /**
600 * append bytes at the end.
601 */
602 void grow(size_t n) {
603 if (size() > max_size() || max_size() - size() < n) {
604 throw std::length_error("overflow");
605 }
606 v_.resize(v_.size() + n);
607 }
608
609 /**
610 * remove bytes at the end.
611 */
612 void shrink(size_t n) {
613 if (n >= size()) {
614 v_.clear();
615 } else {
616 v_.resize(size() - n);
617 }
618 }
619 /**
620 * remove bytes at the start.
621 */
622 void consume(size_t n) {
623 size_t m = std::min(n, size());
624 if (m == size()) {
625 v_.clear();
626 } else {
627 v_.erase(v_.begin(), std::next(v_.begin(), m));
628 }
629 }
630
631 private:
632 T &v_;
633 const size_t max_size_;
634};
635
636} // namespace impl
637
638// 16.12 buffer.dynamic.vector
639
640template <class T, class Allocator>
642 : public impl::dynamic_buffer_base<std::vector<T, Allocator>> {
643 public:
645 std::vector<T, Allocator>>::dynamic_buffer_base;
646};
647
648// 16.13 buffer.dynamic.string
649
650template <class CharT, class Traits, class Allocator>
652 std::basic_string<CharT, Traits, Allocator>> {
653 public:
655 std::basic_string<CharT, Traits, Allocator>>::dynamic_buffer_base;
656};
657
658// 16.14 [buffer.dynamic.creation]
659
660template <class T, class Allocator>
662 std::vector<T, Allocator> &vec) noexcept {
664}
665
666template <class T, class Allocator>
668 std::vector<T, Allocator> &vec, size_t n) noexcept {
670}
671
672template <class CharT, class Traits, class Allocator>
674 std::basic_string<CharT, Traits, Allocator> &str) noexcept {
676}
677
678template <class CharT, class Traits, class Allocator>
680 std::basic_string<CharT, Traits, Allocator> &str, size_t n) noexcept {
682}
683
684// 17.2 [buffer.stream.transfer.all]
685
687 public:
688 size_t operator()(const std::error_code &ec, size_t /* unused */) const {
689 if (!ec) return std::numeric_limits<size_t>::max();
690
691 return 0;
692 }
693};
694
695// 17.3 [buffer.stream.transfer.at.least]
697 public:
698 explicit transfer_at_least(size_t m) : minimum_{m} {}
699
700 size_t operator()(const std::error_code &ec, size_t n) const {
701 if (!ec && n < minimum_) return std::numeric_limits<size_t>::max();
702
703 return 0;
704 }
705
706 private:
707 size_t minimum_;
708};
709
710// 17.4 [buffer.stream.transfer.exactly]
711
713 public:
714 explicit transfer_exactly(size_t m) : exact_{m} {}
715
716 /**
717 * @returns bytes to transfer
718 */
719 size_t operator()(const std::error_code &ec, size_t n) const {
720 // "unspecified non-zero number"
721 constexpr size_t N = std::numeric_limits<size_t>::max();
722
723 if (!ec && n < exact_) return std::min(exact_ - n, N);
724
725 return 0;
726 }
727
728 private:
729 size_t exact_;
730};
731
732// BufferSequence of prepared buffers
733template <class BufferType>
735 public:
736 using value_type = BufferType;
737
738 // for writev()/sendv() a std::array<> is a good enough as it maps to IOV_MAX
739 // (which may be 16)
740 //
741 // note: for protocol decoding something similar is needed, but it shouldn't
742 // be limited to the number of parts. A Generator would be nice.
743 using storage_type = std::array<BufferType, 16>;
744 using const_iterator = typename storage_type::const_iterator;
745 using iterator = typename storage_type::iterator;
746
747 const_iterator begin() const { return bufs_.begin(); }
748 const_iterator end() const { return std::next(begin(), used_); }
749
751 if (size() == max_size()) {
752 throw std::length_error("size() MUST be less than max_size().");
753 }
754 bufs_[used_++] = std::move(v);
755 }
756
757 // number of buffers
758 size_t size() const noexcept { return used_; }
759 // max number of buffers
760 constexpr size_t max_size() const noexcept { return bufs_.size(); }
761
762 private:
764 size_t used_{0};
765};
766
767// get sequence of buffers given byte-size from another sequence of buffers.
768//
769// input buffer sequence is unchanged.
770//
771// - BufferSequence: ConstBufferSequence or MutableBufferSequence
772// - BufferType: net::const_buffer or net::mutable_buffer
773//
774// Note: mostly used for net::write(), net::read()
775template <class BufferSequence, class BufferType>
777 public:
779
780 consuming_buffers(const BufferSequence &buffers) : buffers_{buffers} {}
781
782 /**
783 * prepare a buffer sequence, skipping the already consumed bytes.
784 *
785 * @param max_size max bytes to take from the buffer sequence
786 *
787 * note: nax_size may be larger than the size of the buffer-sequence
788 */
789 prepared_buffer_type prepare(size_t max_size) {
790 prepared_buffer_type to_bufs;
791
792 auto from_cur = buffer_sequence_begin(buffers_);
793 auto const from_end = buffer_sequence_end(buffers_);
794
795 size_t to_skip = total_consumed();
796
797 for (; (from_cur != from_end) && to_bufs.size() < to_bufs.max_size() &&
798 max_size > 0;
799 ++from_cur) {
800 auto cur_buf = net::buffer(*from_cur);
801
802 if (cur_buf.size() > to_skip) {
803 const size_t avail = cur_buf.size() - to_skip;
804 const size_t to_use = std::min(avail, max_size);
805 to_bufs.push_back(net::buffer(BufferType(cur_buf) + to_skip, to_use));
806 to_skip = 0;
807 max_size -= to_use;
808 } else {
809 to_skip -= cur_buf.size();
810 }
811 }
812 return to_bufs;
813 }
814
815 /**
816 * mark bytes as consumed from the beginning of the unconsumed sequence.
817 *
818 * @param n bytes to consume
819 *
820 * note: n may be larger than the size of the buffer-sequence
821 */
822 void consume(size_t n) { total_consumed_ += n; }
823
824 // sum of all consume()ed bytes
825 size_t total_consumed() const { return total_consumed_; }
826
827 private:
828 const BufferSequence &buffers_;
830};
831
832// 17.5 [buffer.read]
833
834template <class SyncReadStream, class MutableBufferSequence>
836 SyncReadStream &stream, const MutableBufferSequence &buffers)
837 requires(is_mutable_buffer_sequence_v<MutableBufferSequence>)
838{
840 "");
841 return read(stream, buffers, transfer_all());
842}
843
844template <class SyncReadStream, class MutableBufferSequence,
845 class CompletionCondition>
847 SyncReadStream &stream, const MutableBufferSequence &buffers,
848 CompletionCondition cond)
849 requires(is_mutable_buffer_sequence_v<MutableBufferSequence>)
850{
852 "");
853
854 std::error_code ec{};
855
857
858 const size_t total_size = buffer_size(buffers);
859 size_t to_transfer;
860
861 while (0 != (to_transfer = cond(ec, consumable.total_consumed())) &&
862 (consumable.total_consumed() < total_size)) {
863 auto res = stream.read_some(consumable.prepare(to_transfer));
864 if (!res) return res;
865
866 consumable.consume(*res);
867 }
868
869 return {consumable.total_consumed()};
870}
871
872template <class SyncReadStream, class DynamicBuffer>
874 DynamicBuffer &&b)
875 requires(is_dynamic_buffer_v<DynamicBuffer>)
876{
877 return read(stream, std::forward<DynamicBuffer>(b), transfer_all());
878}
879
880template <class SyncReadStream, class DynamicBuffer, class CompletionCondition>
882 DynamicBuffer &&b,
883 CompletionCondition cond)
884 requires(is_dynamic_buffer_v<DynamicBuffer>)
885{
886 std::error_code ec{};
887
888 size_t transferred{};
889 size_t to_transfer;
890
891 while (0 != (to_transfer = cond(ec, transferred)) &&
892 b.size() != b.max_size()) {
893 auto orig_size = b.size();
894 // if there is space available, use that, if not grow by 4k
895 auto avail = b.capacity() - orig_size;
896 size_t grow_size = avail ? avail : 4 * 1024;
897 size_t space_left = b.max_size() - b.size();
898 // limit grow-size by possible space-left
899 grow_size = std::min(grow_size, space_left);
900 // limit grow-size by how much data we still have to read
901 grow_size = std::min(grow_size, to_transfer);
902
903 b.grow(grow_size);
904 auto res = stream.read_some(b.data(orig_size, grow_size));
905 if (!res) {
906 b.shrink(grow_size);
907
908 // if socket was non-blocking and some bytes where already read, return
909 // the success
910 const auto error_code = res.error();
911 if ((error_code == make_error_condition(
912 std::errc::resource_unavailable_try_again) ||
913 error_code ==
914 make_error_condition(std::errc::operation_would_block) ||
915 error_code == net::stream_errc::eof) &&
916 transferred != 0) {
917 return transferred;
918 }
919 return res;
920 }
921
922 transferred += *res;
923
924 b.shrink(grow_size - *res);
925 }
926
927 return {transferred};
928}
929
930// 17.6 [buffer.async.read]
931template <class AsyncReadStream, class DynamicBuffer, class CompletionCondition,
932 class CompletionToken>
933void async_read(AsyncReadStream &stream, DynamicBuffer &&b,
934 CompletionCondition completion_condition,
935 CompletionToken &&token)
936 requires(is_dynamic_buffer_v<DynamicBuffer>)
937{
938 async_completion<CompletionToken, void(std::error_code, size_t)> init{token};
939
940 using compl_handler_type = typename decltype(init)::completion_handler_type;
942 [&stream, b_ = std::forward<DynamicBuffer>(b),
943 compl_cond_ = completion_condition,
944 compl_handler_ = std::forward<compl_handler_type>(
945 init.completion_handler)](std::error_code ec) mutable {
946 if (ec) {
947 compl_handler_(ec, 0);
948 return;
949 }
950
951 const auto res = net::read(stream, b_, compl_cond_);
952
953 if (!res) {
954 compl_handler_(res.error(), 0);
955 } else {
956 compl_handler_({}, res.value());
957 }
958
959 return;
960 });
961
962 return init.result.get();
963}
964
965template <class AsyncReadStream, class DynamicBuffer, class CompletionToken>
966void async_read(AsyncReadStream &stream, DynamicBuffer &&b,
967 CompletionToken &&token)
968 requires(is_dynamic_buffer_v<DynamicBuffer>)
969{
970 return async_read(stream, std::forward<DynamicBuffer>(b), net::transfer_all(),
971 std::forward<CompletionToken>(token));
972}
973
974// 17.7 [buffer.write]
975
976template <class SyncWriteStream, class ConstBufferSequence>
978 SyncWriteStream &stream, const ConstBufferSequence &buffers)
979 requires(is_const_buffer_sequence_v<ConstBufferSequence>)
980{
981 return write(stream, buffers, transfer_all());
982}
983
984template <class SyncWriteStream, class ConstBufferSequence,
985 class CompletionCondition>
987 SyncWriteStream &stream, const ConstBufferSequence &buffers,
988 CompletionCondition cond)
989 requires(is_const_buffer_sequence_v<ConstBufferSequence>)
990{
991 std::error_code ec{};
992
994
995 const size_t total_size = buffer_size(buffers);
996 size_t to_transfer;
997
998 while (0 != (to_transfer = cond(ec, consumable.total_consumed())) &&
999 (consumable.total_consumed() < total_size)) {
1000 auto res = stream.write_some(consumable.prepare(to_transfer));
1001 if (!res) {
1002 ec = res.error();
1003 } else {
1004 consumable.consume(*res);
1005 }
1006 }
1007
1008 // if there is an error and it isn't EAGAIN|EWOULDBLOCK, return it.
1009 // if it is EAGAIN|EWOULDBLOCK return it only if nothing was transferred.
1010 if (ec &&
1011 ((ec != make_error_condition(std::errc::resource_unavailable_try_again) &&
1012 ec != make_error_condition(std::errc::operation_would_block)) ||
1013 consumable.total_consumed() == 0)) {
1014 return stdx::unexpected(ec);
1015 } else {
1016 return {consumable.total_consumed()};
1017 }
1018}
1019
1020template <class SyncWriteStream, class DynamicBuffer>
1022 DynamicBuffer &&b)
1023 requires(is_dynamic_buffer_v<DynamicBuffer>)
1024{
1025 return write(stream, std::forward<DynamicBuffer>(b), transfer_all());
1026}
1027
1028template <class SyncWriteStream, class DynamicBuffer, class CompletionCondition>
1030 DynamicBuffer &&b,
1031 CompletionCondition cond)
1032 requires(is_dynamic_buffer_v<DynamicBuffer>)
1033{
1034 std::error_code ec{};
1035
1036 size_t to_transfer;
1037 size_t transferred{};
1038
1039 while (0 != (to_transfer = cond(ec, transferred)) && (b.size() != 0)) {
1040 auto res = stream.write_some(b.data(0, std::min(b.size(), to_transfer)));
1041 if (!res) {
1042 ec = res.error();
1043 } else {
1044 transferred += *res;
1045
1046 b.consume(*res);
1047 }
1048 }
1049
1050 // if there is an error and it isn't EAGAIN|EWOULDBLOCK, return it.
1051 // if it is EAGAIN|EWOULDBLOCK return it only if nothing was transferred.
1052 if (ec &&
1053 ((ec != make_error_condition(std::errc::resource_unavailable_try_again) &&
1054 ec != make_error_condition(std::errc::operation_would_block)) ||
1055 transferred == 0)) {
1056 return stdx::unexpected(ec);
1057 } else {
1058 return transferred;
1059 }
1060}
1061
1062// 17.8 [buffer.async.write]
1063//
1064template <class AsyncWriteStream, class ConstBufferSequence,
1065 class CompletionCondition, class CompletionToken>
1066void async_write(AsyncWriteStream &stream, const ConstBufferSequence &buffers,
1067 CompletionCondition cond, CompletionToken &&token)
1068 requires(is_const_buffer_sequence_v<ConstBufferSequence>)
1069{
1070 async_completion<CompletionToken, void(std::error_code, size_t)> init{token};
1071
1072 stream.async_wait(
1074 [&stream, &buffers, cond,
1075 compl_handler = std::move(init.completion_handler)](std::error_code ec) {
1076 if (ec) {
1077 compl_handler(ec, 0);
1078 return;
1079 }
1080
1081 const auto res = net::write(stream, buffers, cond);
1082
1083 if (!res) {
1084 compl_handler(res.error(), 0);
1085 } else {
1086 compl_handler({}, res.value());
1087 }
1088
1089 return;
1090 });
1091
1092 return init.result.get();
1093}
1094
1095template <class AsyncWriteStream, class ConstBufferSequence,
1096 class CompletionToken>
1097void async_write(AsyncWriteStream &stream, const ConstBufferSequence &buffers,
1098 CompletionToken &&token)
1099 requires(is_const_buffer_sequence_v<ConstBufferSequence>)
1100{
1101 return async_write(stream, buffers, net::transfer_all(),
1102 std::forward<CompletionToken>(token));
1103}
1104
1105template <class AsyncWriteStream, class DynamicBuffer,
1106 class CompletionCondition, class CompletionToken>
1107void async_write(AsyncWriteStream &stream, DynamicBuffer &&b,
1108 CompletionCondition cond, CompletionToken &&token)
1109 requires(is_dynamic_buffer_v<DynamicBuffer>)
1110{
1111 async_completion<CompletionToken, void(std::error_code, size_t)> init{token};
1112
1113 using compl_handler_type = typename decltype(init)::completion_handler_type;
1114
1116 [&stream, buf = std::forward<DynamicBuffer>(b), cond,
1117 compl_handler = std::forward<compl_handler_type>(
1118 init.completion_handler)](std::error_code ec) mutable {
1119 if (ec) {
1120 compl_handler(ec, 0);
1121 return;
1122 }
1123
1124 const auto res = net::write(
1125 stream, std::forward<DynamicBuffer>(buf), cond);
1126
1127 if (!res) {
1128 compl_handler(res.error(), 0);
1129 } else {
1130 compl_handler({}, res.value());
1131 }
1132
1133 return;
1134 });
1135
1136 return init.result.get();
1137}
1138
1139template <class AsyncWriteStream, class DynamicBuffer, class CompletionToken>
1140void async_write(AsyncWriteStream &stream, DynamicBuffer &&b,
1141 CompletionToken &&token)
1142 requires(is_dynamic_buffer_v<DynamicBuffer>)
1143{
1144 return async_write(stream, std::forward<DynamicBuffer>(b),
1145 net::transfer_all(), std::forward<CompletionToken>(token));
1146}
1147
1148// 17.9 [buffer.read.until] not-implemented-yet
1149
1150// 17.10 [buffer.async.read.until] not-implemented-yet
1151
1152} // namespace net
1153
1154#endif
static mysql_service_status_t init()
Component initialization.
Definition: audit_api_message_emit.cc:571
Definition: executor.h:72
Definition: buffer.h:135
const_buffer(const mutable_buffer &b) noexcept
Definition: buffer.h:139
const void * data() const noexcept
Definition: buffer.h:142
const void * data_
Definition: buffer.h:153
size_t size() const noexcept
Definition: buffer.h:143
size_t size_
Definition: buffer.h:154
const_buffer() noexcept
Definition: buffer.h:137
const_buffer(const void *p, size_t n) noexcept
Definition: buffer.h:138
const_buffer & operator+=(size_t n) noexcept
Definition: buffer.h:145
Definition: buffer.h:776
size_t total_consumed() const
Definition: buffer.h:825
void consume(size_t n)
mark bytes as consumed from the beginning of the unconsumed sequence.
Definition: buffer.h:822
const BufferSequence & buffers_
Definition: buffer.h:828
consuming_buffers(const BufferSequence &buffers)
Definition: buffer.h:780
prepared_buffer_type prepare(size_t max_size)
prepare a buffer sequence, skipping the already consumed bytes.
Definition: buffer.h:789
size_t total_consumed_
Definition: buffer.h:829
Definition: buffer.h:652
Definition: buffer.h:642
Definition: buffer.h:564
T & v_
Definition: buffer.h:632
const_buffers_type data(size_t pos, size_t n) const noexcept
Definition: buffer.h:591
size_t max_size() const noexcept
max number of bytes.
Definition: buffer.h:582
void grow(size_t n)
append bytes at the end.
Definition: buffer.h:602
dynamic_buffer_base(T &v) noexcept
Definition: buffer.h:569
void consume(size_t n)
remove bytes at the start.
Definition: buffer.h:622
dynamic_buffer_base(T &v, size_t max_size) noexcept
Definition: buffer.h:571
void shrink(size_t n)
remove bytes at the end.
Definition: buffer.h:612
mutable_buffers_type data(size_t pos, size_t n)
Definition: buffer.h:595
const size_t max_size_
Definition: buffer.h:633
size_t size() const noexcept
number of bytes.
Definition: buffer.h:577
size_t capacity() const noexcept
max number of bytes without requiring reallocation.
Definition: buffer.h:587
Definition: buffer.h:113
mutable_buffer(void *p, size_t n) noexcept
Definition: buffer.h:117
mutable_buffer & operator+=(size_t n) noexcept
Definition: buffer.h:122
size_t size_
Definition: buffer.h:130
void * data() const noexcept
Definition: buffer.h:119
mutable_buffer() noexcept
Definition: buffer.h:115
void * data_
Definition: buffer.h:129
size_t size() const noexcept
Definition: buffer.h:120
Definition: buffer.h:734
const_iterator begin() const
Definition: buffer.h:747
typename storage_type::iterator iterator
Definition: buffer.h:745
BufferType value_type
Definition: buffer.h:736
constexpr size_t max_size() const noexcept
Definition: buffer.h:760
size_t used_
Definition: buffer.h:764
typename storage_type::const_iterator const_iterator
Definition: buffer.h:744
void push_back(value_type &&v)
Definition: buffer.h:750
size_t size() const noexcept
Definition: buffer.h:758
std::array< BufferType, 16 > storage_type
Definition: buffer.h:743
const_iterator end() const
Definition: buffer.h:748
storage_type bufs_
Definition: buffer.h:763
Definition: buffer.h:686
size_t operator()(const std::error_code &ec, size_t) const
Definition: buffer.h:688
Definition: buffer.h:696
size_t minimum_
Definition: buffer.h:707
size_t operator()(const std::error_code &ec, size_t n) const
Definition: buffer.h:700
transfer_at_least(size_t m)
Definition: buffer.h:698
Definition: buffer.h:712
transfer_exactly(size_t m)
Definition: buffer.h:714
size_t exact_
Definition: buffer.h:729
size_t operator()(const std::error_code &ec, size_t n) const
Definition: buffer.h:719
constexpr const error_type & error() const &
Definition: expected.h:755
const char * p
Definition: ctype-mb.cc:1225
if(!(yy_init))
Definition: lexyy.cc:1144
bool equivalent(const MDL_ticket *a, const MDL_ticket *b, enum_mdl_duration target_duration)
Definition: mdl.cc:2617
void copy(Shards< COUNT > &dst, const Shards< COUNT > &src) noexcept
Copy the counters, overwrite destination.
Definition: ut0counter.h:354
std::atomic< Type > N
Definition: ut0counter.h:225
uint16_t value_type
Definition: vt100.h:184
std::string str(const mysqlrouter::ConfigGenerator::Options::Endpoint &ep)
Definition: config_generator.cc:1117
Definition: buf0block_hint.cc:30
Definition: http_server_component.cc:34
mutable_buffer to_mutable_buffer(T *data, size_t n)
Definition: buffer.h:433
const_buffer to_const_buffer(const T *data, size_t n)
Definition: buffer.h:438
auto dynamic_buffer_requirements(U *__x=nullptr, const U *__const_x=nullptr, size_t __n=0) -> std::enable_if_t< std::conjunction< std::is_copy_constructible< U >, is_const_buffer_sequence< typename T::const_buffers_type >, is_mutable_buffer_sequence< typename T::mutable_buffers_type >, std::is_same< decltype(__const_x->size()), size_t >, std::is_same< decltype(__const_x->max_size()), size_t >, std::is_same< decltype(__const_x->capacity()), size_t >, std::is_same< decltype(__const_x->data(__n, __n)), typename T::const_buffers_type >, std::is_same< decltype(__x->data(__n, __n)), typename T::mutable_buffers_type >, std::is_void< decltype(__x->grow(__n))>, std::is_void< decltype(__x->shrink(__n))>, std::is_void< decltype(__x->consume(__n))> >::value >
std::bool_constant< std::conjunction_v< std::is_same< Begin, End >, std::is_convertible< typename std::iterator_traits< Begin >::value_type, BufferType > > > buffer_sequence_requirements
Definition: buffer.h:235
Definition: buffer.h:45
const std::error_category & stream_category() noexcept
Definition: buffer.h:61
size_t buffer_size< mutable_buffer >(const mutable_buffer &b) noexcept
Definition: buffer.h:332
constexpr bool is_const_buffer_sequence_v
Definition: buffer.h:163
constexpr bool is_dynamic_buffer_v
Definition: buffer.h:176
void async_read(AsyncReadStream &stream, DynamicBuffer &&b, CompletionCondition completion_condition, CompletionToken &&token)
Definition: buffer.h:933
stdx::expected< size_t, std::error_code > write(SyncWriteStream &stream, const ConstBufferSequence &buffers)
Definition: buffer.h:977
const const_buffer * buffer_sequence_end(const const_buffer &b) noexcept
Definition: buffer.h:185
stream_errc
Definition: buffer.h:49
dynamic_vector_buffer< T, Allocator > dynamic_buffer(std::vector< T, Allocator > &vec) noexcept
Definition: buffer.h:661
mutable_buffer buffer(void *p, size_t n) noexcept
Definition: buffer.h:418
const const_buffer * buffer_sequence_begin(const const_buffer &b) noexcept
Definition: buffer.h:180
constexpr bool is_mutable_buffer_sequence_v
Definition: buffer.h:169
size_t buffer_copy(const MutableBufferSequence &dest, const ConstBufferSequence &src, const size_t max_size) noexcept
copy bytes from a ConstBufferSequence to a MutableBufferSequence.
Definition: buffer.h:349
size_t buffer_size(const ConstBufferSequence &buffers) noexcept
Definition: buffer.h:313
stdx::expected< size_t, std::error_code > read(SyncReadStream &stream, const MutableBufferSequence &buffers)
Definition: buffer.h:835
void async_write(AsyncWriteStream &stream, const ConstBufferSequence &buffers, CompletionCondition cond, CompletionToken &&token)
Definition: buffer.h:1066
size_t buffer_size< const_buffer >(const const_buffer &b) noexcept
Definition: buffer.h:327
mutable_buffer operator+(const mutable_buffer &b, size_t n) noexcept
Definition: buffer.h:398
void async_write(AsyncWriteStream &stream, DynamicBuffer &&b, CompletionToken &&token)
Definition: buffer.h:1140
std::error_condition make_error_condition(net::stream_errc e) noexcept
Definition: buffer.h:107
std::error_code make_error_code(net::stream_errc e) noexcept
Definition: buffer.h:103
Definition: gcs_xcom_synode.h:64
unexpected(E) -> unexpected< E >
required string type
Definition: replication_group_member_actions.proto:34
case opt name
Definition: sslopt-case.h:29
Definition: buffer.h:238
Definition: buffer.h:247
Definition: buffer.h:263
Definition: buffer.h:259
Definition: buffer.h:308
Definition: buffer.h:256
Definition: dtoa.cc:595
int n
Definition: xcom_base.cc:509