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