MySQL 9.0.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>
835std::enable_if_t<is_mutable_buffer_sequence<MutableBufferSequence>::value,
837read(SyncReadStream &stream, const MutableBufferSequence &buffers) {
839 "");
840 return read(stream, buffers, transfer_all());
841}
842
843template <class SyncReadStream, class MutableBufferSequence,
844 class CompletionCondition>
845std::enable_if_t<is_mutable_buffer_sequence<MutableBufferSequence>::value,
847read(SyncReadStream &stream, const MutableBufferSequence &buffers,
848 CompletionCondition cond) {
850 "");
851
852 std::error_code ec{};
853
855
856 const size_t total_size = buffer_size(buffers);
857 size_t to_transfer;
858
859 while (0 != (to_transfer = cond(ec, consumable.total_consumed())) &&
860 (consumable.total_consumed() < total_size)) {
861 auto res = stream.read_some(consumable.prepare(to_transfer));
862 if (!res) return res;
863
864 consumable.consume(*res);
865 }
866
867 return {consumable.total_consumed()};
868}
869
870template <class SyncReadStream, class DynamicBuffer>
871std::enable_if_t<is_dynamic_buffer<std::decay_t<DynamicBuffer>>::value,
873read(SyncReadStream &stream, DynamicBuffer &&b) {
874 return read(stream, b, transfer_all());
875}
876
877template <class SyncReadStream, class DynamicBuffer, class CompletionCondition>
878std::enable_if_t<is_dynamic_buffer<std::decay_t<DynamicBuffer>>::value,
880read(SyncReadStream &stream, DynamicBuffer &&b, CompletionCondition cond) {
881 std::error_code ec{};
882
883 size_t transferred{};
884 size_t to_transfer;
885
886 while (0 != (to_transfer = cond(ec, transferred)) &&
887 b.size() != b.max_size()) {
888 auto orig_size = b.size();
889 // if there is space available, use that, if not grow by 4k
890 auto avail = b.capacity() - orig_size;
891 size_t grow_size = avail ? avail : 4 * 1024;
892 size_t space_left = b.max_size() - b.size();
893 // limit grow-size by possible space-left
894 grow_size = std::min(grow_size, space_left);
895 // limit grow-size by how much data we still have to read
896 grow_size = std::min(grow_size, to_transfer);
897
898 b.grow(grow_size);
899 auto res = stream.read_some(b.data(orig_size, grow_size));
900 if (!res) {
901 b.shrink(grow_size);
902
903 // if socket was non-blocking and some bytes where already read, return
904 // the success
905 const auto error_code = res.error();
906 if ((error_code == make_error_condition(
907 std::errc::resource_unavailable_try_again) ||
908 error_code ==
909 make_error_condition(std::errc::operation_would_block) ||
910 error_code == net::stream_errc::eof) &&
911 transferred != 0) {
912 return transferred;
913 }
914 return res;
915 }
916
917 transferred += *res;
918
919 b.shrink(grow_size - *res);
920 }
921
922 return {transferred};
923}
924
925// 17.6 [buffer.async.read]
926template <class AsyncReadStream, class DynamicBuffer, class CompletionCondition,
927 class CompletionToken>
928std::enable_if_t<is_dynamic_buffer<DynamicBuffer>::value, void> async_read(
929 AsyncReadStream &stream, DynamicBuffer &&b,
930 CompletionCondition completion_condition, CompletionToken &&token) {
931 async_completion<CompletionToken, void(std::error_code, size_t)> init{token};
932
933 using compl_handler_type = typename decltype(init)::completion_handler_type;
934
935 class Completor {
936 public:
937 Completor(AsyncReadStream &stream, DynamicBuffer &&b,
938 CompletionCondition compl_cond,
939 compl_handler_type &&compl_handler)
940 : stream_{stream},
941 b_{std::forward<DynamicBuffer>(b)},
942 compl_cond_{compl_cond},
943 compl_handler_(std::forward<compl_handler_type>(compl_handler)) {}
944
945 Completor(const Completor &) = delete;
946 Completor(Completor &&) = default;
947
948 void operator()(std::error_code ec) {
949 if (ec) {
950 compl_handler_(ec, 0);
951 return;
952 }
953
954 const auto res = net::read(stream_, b_, compl_cond_);
955
956 if (!res) {
957 compl_handler_(res.error(), 0);
958 } else {
959 compl_handler_({}, res.value());
960 }
961
962 return;
963 }
964
965 private:
966 AsyncReadStream &stream_;
967 DynamicBuffer b_;
968 CompletionCondition compl_cond_;
969 compl_handler_type compl_handler_;
970 };
971
972 stream.async_wait(
974 Completor(stream, std::forward<DynamicBuffer>(b), completion_condition,
975 std::move(init.completion_handler)));
976
977 return init.result.get();
978}
979
980template <class AsyncReadStream, class DynamicBuffer, class CompletionToken>
981std::enable_if_t<is_dynamic_buffer<DynamicBuffer>::value, void> async_read(
982 AsyncReadStream &stream, DynamicBuffer &&b, CompletionToken &&token) {
983 return async_read(stream, std::forward<DynamicBuffer>(b), net::transfer_all(),
984 std::forward<CompletionToken>(token));
985}
986
987// 17.7 [buffer.write]
988
989template <class SyncWriteStream, class ConstBufferSequence>
990std::enable_if_t<is_const_buffer_sequence_v<ConstBufferSequence>,
992write(SyncWriteStream &stream, const ConstBufferSequence &buffers) {
993 return write(stream, buffers, transfer_all());
994}
995
996template <class SyncWriteStream, class ConstBufferSequence,
997 class CompletionCondition>
998std::enable_if_t<is_const_buffer_sequence_v<ConstBufferSequence>,
1000write(SyncWriteStream &stream, const ConstBufferSequence &buffers,
1001 CompletionCondition cond) {
1002 std::error_code ec{};
1003
1005
1006 const size_t total_size = buffer_size(buffers);
1007 size_t to_transfer;
1008
1009 while (0 != (to_transfer = cond(ec, consumable.total_consumed())) &&
1010 (consumable.total_consumed() < total_size)) {
1011 auto res = stream.write_some(consumable.prepare(to_transfer));
1012 if (!res) {
1013 ec = res.error();
1014 } else {
1015 consumable.consume(*res);
1016 }
1017 }
1018
1019 // if there is an error and it isn't EAGAIN|EWOULDBLOCK, return it.
1020 // if it is EAGAIN|EWOULDBLOCK return it only if nothing was transferred.
1021 if (ec &&
1022 ((ec != make_error_condition(std::errc::resource_unavailable_try_again) &&
1023 ec != make_error_condition(std::errc::operation_would_block)) ||
1024 consumable.total_consumed() == 0)) {
1025 return stdx::unexpected(ec);
1026 } else {
1027 return {consumable.total_consumed()};
1028 }
1029}
1030
1031template <class SyncWriteStream, class DynamicBuffer>
1032std::enable_if_t<is_dynamic_buffer<DynamicBuffer>::value,
1034write(SyncWriteStream &stream, DynamicBuffer &&b) {
1035 return write(stream, std::forward<DynamicBuffer>(b), transfer_all());
1036}
1037
1038template <class SyncWriteStream, class DynamicBuffer, class CompletionCondition>
1039std::enable_if_t<is_dynamic_buffer<DynamicBuffer>::value,
1041write(SyncWriteStream &stream, DynamicBuffer &&b, CompletionCondition cond) {
1042 std::error_code ec{};
1043
1044 size_t to_transfer;
1045 size_t transferred{};
1046
1047 while (0 != (to_transfer = cond(ec, transferred)) && (b.size() != 0)) {
1048 auto res = stream.write_some(b.data(0, std::min(b.size(), to_transfer)));
1049 if (!res) {
1050 ec = res.error();
1051 } else {
1052 transferred += *res;
1053
1054 b.consume(*res);
1055 }
1056 }
1057
1058 // if there is an error and it isn't EAGAIN|EWOULDBLOCK, return it.
1059 // if it is EAGAIN|EWOULDBLOCK return it only if nothing was transferred.
1060 if (ec &&
1061 ((ec != make_error_condition(std::errc::resource_unavailable_try_again) &&
1062 ec != make_error_condition(std::errc::operation_would_block)) ||
1063 transferred == 0)) {
1064 return stdx::unexpected(ec);
1065 } else {
1066 return transferred;
1067 }
1068}
1069
1070// 17.8 [buffer.async.write]
1071//
1072template <class AsyncWriteStream, class ConstBufferSequence,
1073 class CompletionCondition, class CompletionToken>
1074std::enable_if_t<is_const_buffer_sequence_v<ConstBufferSequence>, void>
1075async_write(AsyncWriteStream &stream, const ConstBufferSequence &buffers,
1076 CompletionCondition cond, CompletionToken &&token) {
1077 async_completion<CompletionToken, void(std::error_code, size_t)> init{token};
1078
1079 stream.async_wait(
1081 [&stream, &buffers, cond,
1082 compl_handler = std::move(init.completion_handler)](std::error_code ec) {
1083 if (ec) {
1084 compl_handler(ec, 0);
1085 return;
1086 }
1087
1088 const auto res = net::write(stream, buffers, cond);
1089
1090 if (!res) {
1091 compl_handler(res.error(), 0);
1092 } else {
1093 compl_handler({}, res.value());
1094 }
1095
1096 return;
1097 });
1098
1099 return init.result.get();
1100}
1101
1102template <class AsyncWriteStream, class ConstBufferSequence,
1103 class CompletionToken>
1104std::enable_if_t<is_const_buffer_sequence_v<ConstBufferSequence>, void>
1105async_write(AsyncWriteStream &stream, const ConstBufferSequence &buffers,
1106 CompletionToken &&token) {
1107 return async_write(stream, buffers, net::transfer_all(),
1108 std::forward<CompletionToken>(token));
1109}
1110
1111template <class AsyncWriteStream, class DynamicBuffer,
1112 class CompletionCondition, class CompletionToken>
1113std::enable_if_t<is_dynamic_buffer<DynamicBuffer>::value, void> async_write(
1114 AsyncWriteStream &stream, DynamicBuffer &&b, CompletionCondition cond,
1115 CompletionToken &&token) {
1116 async_completion<CompletionToken, void(std::error_code, size_t)> init{token};
1117
1118 using compl_handler_type = typename decltype(init)::completion_handler_type;
1119
1120 class Completor {
1121 public:
1122 Completor(AsyncWriteStream &stream, DynamicBuffer &&b,
1123 CompletionCondition cond, compl_handler_type &&compl_handler)
1124 : stream_{stream},
1125 b_{std::forward<DynamicBuffer>(b)},
1126 cond_{cond},
1127 compl_handler_(std::forward<compl_handler_type>(compl_handler)) {}
1128
1129 Completor(const Completor &) = delete;
1130 Completor(Completor &&) = default;
1131
1132 void operator()(std::error_code ec) {
1133 if (ec) {
1134 compl_handler_(ec, 0);
1135 return;
1136 }
1137
1138 const auto res =
1139 net::write(stream_, std::forward<DynamicBuffer>(b_), cond_);
1140
1141 if (!res) {
1142 compl_handler_(res.error(), 0);
1143 } else {
1144 compl_handler_({}, res.value());
1145 }
1146
1147 return;
1148 }
1149
1150 private:
1151 AsyncWriteStream &stream_;
1152 DynamicBuffer b_;
1153 CompletionCondition cond_;
1154 compl_handler_type compl_handler_;
1155 };
1156
1158 Completor(stream, std::forward<DynamicBuffer>(b), cond,
1159 std::move(init.completion_handler)));
1160
1161 return init.result.get();
1162}
1163
1164template <class AsyncWriteStream, class DynamicBuffer, class CompletionToken>
1165std::enable_if_t<is_dynamic_buffer<DynamicBuffer>::value, void> async_write(
1166 AsyncWriteStream &stream, DynamicBuffer &&b, CompletionToken &&token) {
1167 return async_write(stream, std::forward<DynamicBuffer>(b),
1168 net::transfer_all(), std::forward<CompletionToken>(token));
1169}
1170
1171// 17.9 [buffer.read.until] not-implemented-ye
1172
1173// 17.10 [buffer.async.read.until] not-implemented-yet
1174
1175} // namespace net
1176
1177#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
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:2615
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:1081
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
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
std::enable_if_t< is_dynamic_buffer< DynamicBuffer >::value, void > async_write(AsyncWriteStream &stream, DynamicBuffer &&b, CompletionToken &&token)
Definition: buffer.h:1165
std::enable_if_t< is_const_buffer_sequence_v< ConstBufferSequence >, stdx::expected< size_t, std::error_code > > write(SyncWriteStream &stream, const ConstBufferSequence &buffers)
Definition: buffer.h:992
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
std::enable_if_t< is_dynamic_buffer< DynamicBuffer >::value, void > async_read(AsyncReadStream &stream, DynamicBuffer &&b, CompletionCondition completion_condition, CompletionToken &&token)
Definition: buffer.h:928
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
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
std::enable_if_t< is_const_buffer_sequence_v< ConstBufferSequence >, void > async_write(AsyncWriteStream &stream, const ConstBufferSequence &buffers, CompletionCondition cond, CompletionToken &&token)
Definition: buffer.h:1075
std::error_condition make_error_condition(net::stream_errc e) noexcept
Definition: buffer.h:107
std::enable_if_t< is_mutable_buffer_sequence< MutableBufferSequence >::value, stdx::expected< size_t, std::error_code > > read(SyncReadStream &stream, const MutableBufferSequence &buffers)
Definition: buffer.h:837
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:588
int n
Definition: xcom_base.cc:509