MySQL 8.2.0
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::bool_constant<std::conjunction_v<
228 // check if buffer_sequence_begin(T &) and buffer_sequence_end(T &)
229 // exist and return the same type
230 std::is_same<Begin, End>,
231 // check if ::value_type of the retval of buffer_sequence_begin() can be
232 // converted into a BufferType
233 std::is_convertible<typename std::iterator_traits<Begin>::value_type,
234 BufferType>>>;
235
236template <class T, class BufferType, class = void>
237struct is_buffer_sequence : std::false_type {};
238
239template <class T, class BufferType>
241 T, BufferType, std::void_t<buffer_sequence_requirements<T, BufferType>>>
243
244template <class T>
246 : is_buffer_sequence<T, net::const_buffer>::type {};
247
248template <class T>
250 : is_buffer_sequence<T, net::mutable_buffer>::type {};
251
252} // namespace impl
253
254template <class T>
256
257template <class T>
259
260namespace impl {
261template <class T, class = void>
262struct is_dynamic_buffer : std::false_type {};
263
264/*
265 * helper function for requirement checks.
266 *
267 * - function isn't implemented, just declared to type-check
268 * - function params are default initialized, never have to be specified
269 * - function params exist only to apply type-checks against them and pass them
270 * as parameter to decltype() like checks
271 */
272template <class T, class U = std::remove_const_t<T>>
273auto dynamic_buffer_requirements(U *__x = nullptr, const U *__const_x = nullptr,
274 size_t __n = 0)
275 -> std::enable_if_t<std::conjunction<
276 // is copy constructible
277 std::is_copy_constructible<U>,
278 // has a const_buffers_type that's a const_buffer_sequence
280 // has a mutable_buffers_type that's a mutable_buffer_sequence
282 // has 'size_t size() const' member
283 std::is_same<decltype(__const_x->size()), size_t>,
284 // has 'size_t max_size() const' member
285 std::is_same<decltype(__const_x->max_size()), size_t>,
286 // has 'size_t capacity() const' member
287 std::is_same<decltype(__const_x->capacity()), size_t>,
288 // has 'const_buffer_type data(size_t, size_t) const' member
289 std::is_same<decltype(__const_x->data(__n, __n)),
290 typename T::const_buffers_type>,
291 // has 'mutable_buffers_type data(size_t, size_t)' member
292 std::is_same<decltype(__x->data(__n, __n)),
293 typename T::mutable_buffers_type>,
294 // has 'void grow(size_t)' member
295 std::is_void<decltype(__x->grow(__n))>,
296 // has 'void shrink(size_t)' member
297 std::is_void<decltype(__x->shrink(__n))>,
298 // has 'void consume(size_t)' member
299 std::is_void<decltype(__x->consume(__n))>>::value>;
300
301template <class T>
303 : std::true_type {};
304} // namespace impl
305
306template <class T>
308
309// 16.8 [buffer.size]
310
311template <class ConstBufferSequence>
312inline size_t buffer_size(const ConstBufferSequence &buffers) noexcept {
313 size_t total_size{0};
314 auto end = buffer_sequence_end(buffers);
315
316 for (auto i = buffer_sequence_begin(buffers); i != end; ++i) {
317 const_buffer b(*i);
318
319 total_size += b.size();
320 }
321
322 return total_size;
323}
324
325template <>
326inline size_t buffer_size<const_buffer>(const const_buffer &b) noexcept {
327 return b.size();
328}
329
330template <>
331inline size_t buffer_size<mutable_buffer>(const mutable_buffer &b) noexcept {
332 return b.size();
333}
334
335/**
336 * copy bytes from a ConstBufferSequence to a MutableBufferSequence.
337 *
338 * copies min(max_bytes, buffer_size(src), buffer_size(dest)) bytes
339 *
340 * @param dest buffer-sequence to copy to
341 * @param src buffer-sequence to copy from
342 * @param max_size max bytes to copy
343 * @return bytes transferred from src to dest
344 *
345 * see: 16.9 [buffer.copy]
346 */
347template <class MutableBufferSequence, class ConstBufferSequence>
348size_t buffer_copy(const MutableBufferSequence &dest,
349 const ConstBufferSequence &src,
350 const size_t max_size) noexcept {
351 size_t transfered{0};
352 auto dest_cur = buffer_sequence_begin(dest);
353 auto const dest_end = buffer_sequence_end(dest);
354 auto src_cur = buffer_sequence_begin(src);
355 auto const src_end = buffer_sequence_end(src);
356
357 const_buffer src_buf;
358 mutable_buffer dest_buf;
359
360 while (transfered < max_size) {
361 // if buffer is empty, fetch the next one, if there is one
362 if (src_buf.size() == 0) {
363 if (src_cur == src_end) break;
364 src_buf = const_buffer(*src_cur++);
365 }
366 if (dest_buf.size() == 0) {
367 if (dest_cur == dest_end) break;
368 dest_buf = mutable_buffer(*dest_cur++);
369 }
370
371 size_t to_copy = std::min(dest_buf.size(), src_buf.size());
372 to_copy = std::min(to_copy, max_size - transfered);
373
374 // use std::copy() instead of std::memcpy() as it will be constexpr in C++20
375 // and results in the same code as a memcpy() already
376 std::copy(static_cast<const char *>(src_buf.data()),
377 std::next(static_cast<const char *>(src_buf.data()), to_copy),
378 static_cast<char *>(dest_buf.data()));
379
380 src_buf += to_copy;
381 dest_buf += to_copy;
382
383 transfered += to_copy;
384 }
385
386 return transfered;
387}
388
389template <class MutableBufferSequence, class ConstBufferSequence>
390size_t buffer_copy(const MutableBufferSequence &dest,
391 const ConstBufferSequence &src) noexcept {
392 return buffer_copy(dest, src, std::numeric_limits<size_t>::max());
393}
394
395// 16.10 [buffer.arithmetic]
396
397inline mutable_buffer operator+(const mutable_buffer &b, size_t n) noexcept {
398 const size_t inc_size = std::min(n, b.size());
399
400 return {static_cast<char *>(b.data()) + inc_size, b.size() - inc_size};
401}
402inline mutable_buffer operator+(size_t n, const mutable_buffer &b) noexcept {
403 return operator+(b, n);
404}
405
406inline const_buffer operator+(const const_buffer &b, size_t n) noexcept {
407 const size_t inc_size = std::min(n, b.size());
408 return {static_cast<const char *>(b.data()) + inc_size, b.size() - inc_size};
409}
410
411inline const_buffer operator+(size_t n, const const_buffer &b) noexcept {
412 return operator+(b, n);
413}
414
415// 16.11 [buffer.creation]
416
417inline mutable_buffer buffer(void *p, size_t n) noexcept { return {p, n}; }
418inline const_buffer buffer(const void *p, size_t n) noexcept { return {p, n}; }
419
420inline mutable_buffer buffer(const mutable_buffer &b) noexcept { return b; }
421inline mutable_buffer buffer(const mutable_buffer &b, size_t n) noexcept {
422 return {b.data(), std::min(b.size(), n)};
423}
424
425inline const_buffer buffer(const const_buffer &b) noexcept { return b; }
426inline const_buffer buffer(const const_buffer &b, size_t n) noexcept {
427 return {b.data(), std::min(b.size(), n)};
428}
429
430namespace impl {
431template <typename T>
432inline mutable_buffer to_mutable_buffer(T *data, size_t n) {
433 return {n ? data : nullptr, sizeof(*data) * n};
434}
435
436template <typename T>
437inline const_buffer to_const_buffer(const T *data, size_t n) {
438 return {n ? data : nullptr, sizeof(*data) * n};
439}
440} // namespace impl
441
442template <class T, size_t N>
443inline mutable_buffer buffer(T (&data)[N]) noexcept {
444 return impl::to_mutable_buffer(data, N);
445}
446
447template <class T, size_t N>
448inline const_buffer buffer(const T (&data)[N]) noexcept {
449 return impl::to_const_buffer(data, N);
450}
451
452template <class T, size_t N>
453inline mutable_buffer buffer(std::array<T, N> &data) noexcept {
454 return impl::to_mutable_buffer(data.data(), N);
455}
456
457template <class T, size_t N>
458inline const_buffer buffer(std::array<const T, N> &data) noexcept {
459 return impl::to_const_buffer(data.data(), N);
460}
461
462template <class T, size_t N>
463inline const_buffer buffer(const std::array<T, N> &data) noexcept {
464 return impl::to_const_buffer(data.data(), N);
465}
466
467template <class T, class Allocator>
468inline mutable_buffer buffer(std::vector<T, Allocator> &data) noexcept {
469 return impl::to_mutable_buffer(data.data(), data.size());
470}
471
472template <class T, class Allocator>
473inline const_buffer buffer(const std::vector<T, Allocator> &data) noexcept {
474 return impl::to_const_buffer(data.data(), data.size());
475}
476
477template <class CharT, class Traits, class Allocator>
479 std::basic_string<CharT, Traits, Allocator> &data) noexcept {
480 return data.empty() ? mutable_buffer{}
481 : impl::to_mutable_buffer(&data.front(), data.size());
482}
483
484template <class CharT, class Traits, class Allocator>
486 const std::basic_string<CharT, Traits, Allocator> &data) noexcept {
487 return data.empty() ? const_buffer{}
488 : impl::to_const_buffer(&data.front(), data.size());
489}
490
491template <class CharT, class Traits>
493 const std::basic_string_view<CharT, Traits> &data) noexcept {
494 return data.empty() ? const_buffer{}
495 : impl::to_const_buffer(data.data(), data.size());
496}
497
498template <class T, std::size_t E>
499inline const_buffer buffer(const stdx::span<T, E> &data) noexcept {
500 return data.empty() ? const_buffer{}
501 : impl::to_const_buffer(data.data(), data.size());
502}
503
504template <class T, size_t N>
505inline mutable_buffer buffer(T (&data)[N], size_t n) noexcept {
506 return buffer(buffer(data), n);
507}
508
509template <class T, size_t N>
510inline const_buffer buffer(const T (&data)[N], size_t n) noexcept {
511 return buffer(buffer(data), n);
512}
513
514template <class T, size_t N>
515inline mutable_buffer buffer(std::array<T, N> &data, size_t n) noexcept {
516 return buffer(buffer(data), n);
517}
518
519template <class T, size_t N>
520inline const_buffer buffer(std::array<const T, N> &data, size_t n) noexcept {
521 return buffer(buffer(data), n);
522}
523
524template <class T, size_t N>
525inline const_buffer buffer(const std::array<T, N> &data, size_t n) noexcept {
526 return buffer(buffer(data), n);
527}
528
529template <class T, class Allocator>
530inline mutable_buffer buffer(std::vector<T, Allocator> &data,
531 size_t n) noexcept {
532 return buffer(buffer(data), n);
533}
534
535template <class T, class Allocator>
536inline const_buffer buffer(const std::vector<T, Allocator> &data,
537 size_t n) noexcept {
538 return buffer(buffer(data), n);
539}
540
541template <class CharT, class Traits, class Allocator>
542inline mutable_buffer buffer(std::basic_string<CharT, Traits, Allocator> &data,
543 size_t n) noexcept {
544 return buffer(buffer(data), n);
545}
546
547template <class CharT, class Traits, class Allocator>
549 const std::basic_string<CharT, Traits, Allocator> &data,
550 size_t n) noexcept {
551 return buffer(buffer(data), n);
552}
553
554template <class T, std::size_t E>
555inline const_buffer buffer(const stdx::span<T, E> &data, size_t n) noexcept {
556 return buffer(buffer(data), n);
557}
558
559namespace impl {
560// base for net::dynamic_vector_buffer and net::dynamic_string_buffer who share
561// the same interface, just differ by storage type
562template <class T>
564 public:
567
568 explicit dynamic_buffer_base(T &v) noexcept
569 : v_{v}, max_size_{v.max_size()} {}
570 dynamic_buffer_base(T &v, size_t max_size) noexcept
571 : v_{v}, max_size_{max_size} {}
572
573 /**
574 * number of bytes.
575 */
576 size_t size() const noexcept { return std::min(v_.size(), max_size_); }
577
578 /**
579 * max number of bytes.
580 */
581 size_t max_size() const noexcept { return max_size_; }
582
583 /**
584 * max number of bytes without requiring reallocation.
585 */
586 size_t capacity() const noexcept {
587 return std::min(v_.capacity(), max_size_);
588 }
589
590 const_buffers_type data(size_t pos, size_t n) const noexcept {
591 return buffer(buffer(v_, max_size_) + pos, n);
592 }
593
594 mutable_buffers_type data(size_t pos, size_t n) {
595 return buffer(buffer(v_, max_size_) + pos, n);
596 }
597
598 /**
599 * append bytes at the end.
600 */
601 void grow(size_t n) {
602 if (size() > max_size() || max_size() - size() < n) {
603 throw std::length_error("overflow");
604 }
605 v_.resize(v_.size() + n);
606 }
607
608 /**
609 * remove bytes at the end.
610 */
611 void shrink(size_t n) {
612 if (n >= size()) {
613 v_.clear();
614 } else {
615 v_.resize(size() - n);
616 }
617 }
618 /**
619 * remove bytes at the start.
620 */
621 void consume(size_t n) {
622 size_t m = std::min(n, size());
623 if (m == size()) {
624 v_.clear();
625 } else {
626 v_.erase(v_.begin(), std::next(v_.begin(), m));
627 }
628 }
629
630 private:
631 T &v_;
632 const size_t max_size_;
633};
634
635} // namespace impl
636
637// 16.12 buffer.dynamic.vector
638
639template <class T, class Allocator>
641 : public impl::dynamic_buffer_base<std::vector<T, Allocator>> {
642 public:
644 std::vector<T, Allocator>>::dynamic_buffer_base;
645};
646
647// 16.13 buffer.dynamic.string
648
649template <class CharT, class Traits, class Allocator>
651 std::basic_string<CharT, Traits, Allocator>> {
652 public:
654 std::basic_string<CharT, Traits, Allocator>>::dynamic_buffer_base;
655};
656
657// 16.14 [buffer.dynamic.creation]
658
659template <class T, class Allocator>
661 std::vector<T, Allocator> &vec) noexcept {
663}
664
665template <class T, class Allocator>
667 std::vector<T, Allocator> &vec, size_t n) noexcept {
669}
670
671template <class CharT, class Traits, class Allocator>
673 std::basic_string<CharT, Traits, Allocator> &str) noexcept {
675}
676
677template <class CharT, class Traits, class Allocator>
679 std::basic_string<CharT, Traits, Allocator> &str, size_t n) noexcept {
681}
682
683// 17.2 [buffer.stream.transfer.all]
684
686 public:
687 size_t operator()(const std::error_code &ec, size_t /* unused */) const {
688 if (!ec) return std::numeric_limits<size_t>::max();
689
690 return 0;
691 }
692};
693
694// 17.3 [buffer.stream.transfer.at.least]
696 public:
697 explicit transfer_at_least(size_t m) : minimum_{m} {}
698
699 size_t operator()(const std::error_code &ec, size_t n) const {
700 if (!ec && n < minimum_) return std::numeric_limits<size_t>::max();
701
702 return 0;
703 }
704
705 private:
706 size_t minimum_;
707};
708
709// 17.4 [buffer.stream.transfer.exactly]
710
712 public:
713 explicit transfer_exactly(size_t m) : exact_{m} {}
714
715 /**
716 * @returns bytes to transfer
717 */
718 size_t operator()(const std::error_code &ec, size_t n) const {
719 // "unspecified non-zero number"
720 constexpr size_t N = std::numeric_limits<size_t>::max();
721
722 if (!ec && n < exact_) return std::min(exact_ - n, N);
723
724 return 0;
725 }
726
727 private:
728 size_t exact_;
729};
730
731// BufferSequence of prepared buffers
732template <class BufferType>
734 public:
735 using value_type = BufferType;
736
737 // for writev()/sendv() a std::array<> is a good enough as it maps to IOV_MAX
738 // (which may be 16)
739 //
740 // note: for protocol decoding something similar is needed, but it shouldn't
741 // be limited to the number of parts. A Generator would be nice.
742 using storage_type = std::array<BufferType, 16>;
743 using const_iterator = typename storage_type::const_iterator;
744 using iterator = typename storage_type::iterator;
745
746 const_iterator begin() const { return bufs_.begin(); }
747 const_iterator end() const { return std::next(begin(), used_); }
748
750 if (size() == max_size()) {
751 throw std::length_error("size() MUST be less than max_size().");
752 }
753 bufs_[used_++] = std::move(v);
754 }
755
756 // number of buffers
757 size_t size() const noexcept { return used_; }
758 // max number of buffers
759 constexpr size_t max_size() const noexcept { return bufs_.size(); }
760
761 private:
763 size_t used_{0};
764};
765
766// get sequence of buffers given byte-size from another sequence of buffers.
767//
768// input buffer sequence is unchanged.
769//
770// - BufferSequence: ConstBufferSequence or MutableBufferSequence
771// - BufferType: net::const_buffer or net::mutable_buffer
772//
773// Note: mostly used for net::write(), net::read()
774template <class BufferSequence, class BufferType>
776 public:
778
779 consuming_buffers(const BufferSequence &buffers) : buffers_{buffers} {}
780
781 /**
782 * prepare a buffer sequence, skipping the already consumed bytes.
783 *
784 * @param max_size max bytes to take from the buffer sequence
785 *
786 * note: nax_size may be larger than the size of the buffer-sequence
787 */
788 prepared_buffer_type prepare(size_t max_size) {
789 prepared_buffer_type to_bufs;
790
791 auto from_cur = buffer_sequence_begin(buffers_);
792 auto const from_end = buffer_sequence_end(buffers_);
793
794 size_t to_skip = total_consumed();
795
796 for (; (from_cur != from_end) && to_bufs.size() < to_bufs.max_size() &&
797 max_size > 0;
798 ++from_cur) {
799 if (from_cur->size() > to_skip) {
800 const size_t avail = from_cur->size() - to_skip;
801 const size_t to_use = std::min(avail, max_size);
802 to_bufs.push_back(
803 net::buffer(BufferType(net::buffer(*from_cur)) + to_skip, to_use));
804 to_skip = 0;
805 max_size -= to_use;
806 } else {
807 to_skip -= from_cur->size();
808 }
809 }
810 return to_bufs;
811 }
812
813 /**
814 * mark bytes as consumed from the beginning of the unconsumed sequence.
815 *
816 * @param n bytes to consume
817 *
818 * note: n may be larger than the size of the buffer-sequence
819 */
820 void consume(size_t n) { total_consumed_ += n; }
821
822 // sum of all consume()ed bytes
823 size_t total_consumed() const { return total_consumed_; }
824
825 private:
826 const BufferSequence &buffers_;
828};
829
830// 17.5 [buffer.read]
831
832template <class SyncReadStream, class MutableBufferSequence>
833std::enable_if_t<is_mutable_buffer_sequence<MutableBufferSequence>::value,
835read(SyncReadStream &stream, const MutableBufferSequence &buffers) {
837 "");
838 return read(stream, buffers, transfer_all());
839}
840
841template <class SyncReadStream, class MutableBufferSequence,
842 class CompletionCondition>
843std::enable_if_t<is_mutable_buffer_sequence<MutableBufferSequence>::value,
845read(SyncReadStream &stream, const MutableBufferSequence &buffers,
846 CompletionCondition cond) {
848 "");
849
850 std::error_code ec{};
851
853
854 const size_t total_size = buffer_size(buffers);
855 size_t to_transfer;
856
857 while (0 != (to_transfer = cond(ec, consumable.total_consumed())) &&
858 (consumable.total_consumed() < total_size)) {
859 auto res = stream.read_some(consumable.prepare(to_transfer));
860 if (!res) return res;
861
862 consumable.consume(*res);
863 }
864
865 return {consumable.total_consumed()};
866}
867
868template <class SyncReadStream, class DynamicBuffer>
869std::enable_if_t<is_dynamic_buffer<std::decay_t<DynamicBuffer>>::value,
871read(SyncReadStream &stream, DynamicBuffer &&b) {
872 return read(stream, b, transfer_all());
873}
874
875template <class SyncReadStream, class DynamicBuffer, class CompletionCondition>
876std::enable_if_t<is_dynamic_buffer<std::decay_t<DynamicBuffer>>::value,
878read(SyncReadStream &stream, DynamicBuffer &&b, CompletionCondition cond) {
879 std::error_code ec{};
880
881 size_t transferred{};
882 size_t to_transfer;
883
884 while (0 != (to_transfer = cond(ec, transferred)) &&
885 b.size() != b.max_size()) {
886 auto orig_size = b.size();
887 // if there is space available, use that, if not grow by 4k
888 auto avail = b.capacity() - orig_size;
889 size_t grow_size = avail ? avail : 4 * 1024;
890 size_t space_left = b.max_size() - b.size();
891 // limit grow-size by possible space-left
892 grow_size = std::min(grow_size, space_left);
893 // limit grow-size by how much data we still have to read
894 grow_size = std::min(grow_size, to_transfer);
895
896 b.grow(grow_size);
897 auto res = stream.read_some(b.data(orig_size, grow_size));
898 if (!res) {
899 b.shrink(grow_size);
900
901 // if socket was non-blocking and some bytes where already read, return
902 // the success
903 const auto ec = res.error();
904 if ((ec == make_error_condition(
905 std::errc::resource_unavailable_try_again) ||
906 ec == make_error_condition(std::errc::operation_would_block) ||
907 ec == net::stream_errc::eof) &&
908 transferred != 0) {
909 return transferred;
910 }
911 return res;
912 }
913
914 transferred += *res;
915
916 b.shrink(grow_size - *res);
917 }
918
919 return {transferred};
920}
921
922// 17.6 [buffer.async.read]
923template <class AsyncReadStream, class DynamicBuffer, class CompletionCondition,
924 class CompletionToken>
925std::enable_if_t<is_dynamic_buffer<DynamicBuffer>::value, void> async_read(
926 AsyncReadStream &stream, DynamicBuffer &&b,
927 CompletionCondition completion_condition, CompletionToken &&token) {
928 async_completion<CompletionToken, void(std::error_code, size_t)> init{token};
929
930 using compl_handler_type = typename decltype(init)::completion_handler_type;
931
932 class Completor {
933 public:
934 Completor(AsyncReadStream &stream, DynamicBuffer &&b,
935 CompletionCondition compl_cond,
936 compl_handler_type &&compl_handler)
937 : stream_{stream},
938 b_{std::forward<DynamicBuffer>(b)},
939 compl_cond_{compl_cond},
940 compl_handler_(std::forward<compl_handler_type>(compl_handler)) {}
941
942 Completor(const Completor &) = delete;
943 Completor(Completor &&) = default;
944
945 void operator()(std::error_code ec) {
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 private:
963 AsyncReadStream &stream_;
964 DynamicBuffer b_;
965 CompletionCondition compl_cond_;
966 compl_handler_type compl_handler_;
967 };
968
969 stream.async_wait(
971 Completor(stream, std::forward<DynamicBuffer>(b), completion_condition,
972 std::move(init.completion_handler)));
973
974 return init.result.get();
975}
976
977template <class AsyncReadStream, class DynamicBuffer, class CompletionToken>
978std::enable_if_t<is_dynamic_buffer<DynamicBuffer>::value, void> async_read(
979 AsyncReadStream &stream, DynamicBuffer &&b, CompletionToken &&token) {
980 return async_read(stream, std::forward<DynamicBuffer>(b), net::transfer_all(),
981 std::forward<CompletionToken>(token));
982}
983
984// 17.7 [buffer.write]
985
986template <class SyncWriteStream, class ConstBufferSequence>
987std::enable_if_t<is_const_buffer_sequence<ConstBufferSequence>::value,
989write(SyncWriteStream &stream, const ConstBufferSequence &buffers) {
990 return write(stream, buffers, transfer_all());
991}
992
993template <class SyncWriteStream, class ConstBufferSequence,
994 class CompletionCondition>
995std::enable_if_t<is_const_buffer_sequence<ConstBufferSequence>::value,
997write(SyncWriteStream &stream, const ConstBufferSequence &buffers,
998 CompletionCondition cond) {
999 std::error_code ec{};
1000
1002
1003 const size_t total_size = buffer_size(buffers);
1004 size_t to_transfer;
1005
1006 while (0 != (to_transfer = cond(ec, consumable.total_consumed())) &&
1007 (consumable.total_consumed() < total_size)) {
1008 auto res = stream.write_some(consumable.prepare(to_transfer));
1009 if (!res) {
1010 ec = res.error();
1011 } else {
1012 consumable.consume(*res);
1013 }
1014 }
1015
1016 // if there is an error and it isn't EAGAIN|EWOULDBLOCK, return it.
1017 // if it is EAGAIN|EWOULDBLOCK return it only if nothing was transferred.
1018 if (ec &&
1019 ((ec != make_error_condition(std::errc::resource_unavailable_try_again) &&
1020 ec != make_error_condition(std::errc::operation_would_block)) ||
1021 consumable.total_consumed() == 0)) {
1022 return stdx::make_unexpected(ec);
1023 } else {
1024 return {consumable.total_consumed()};
1025 }
1026}
1027
1028template <class SyncWriteStream, class DynamicBuffer>
1029std::enable_if_t<is_dynamic_buffer<DynamicBuffer>::value,
1031write(SyncWriteStream &stream, DynamicBuffer &&b) {
1032 return write(stream, std::forward<DynamicBuffer>(b), transfer_all());
1033}
1034
1035template <class SyncWriteStream, class DynamicBuffer, class CompletionCondition>
1036std::enable_if_t<is_dynamic_buffer<DynamicBuffer>::value,
1038write(SyncWriteStream &stream, DynamicBuffer &&b, CompletionCondition cond) {
1039 std::error_code ec{};
1040
1041 size_t to_transfer;
1042 size_t transferred{};
1043
1044 while (0 != (to_transfer = cond(ec, transferred)) && (b.size() != 0)) {
1045 auto res = stream.write_some(b.data(0, std::min(b.size(), to_transfer)));
1046 if (!res) {
1047 ec = res.error();
1048 } else {
1049 transferred += *res;
1050
1051 b.consume(*res);
1052 }
1053 }
1054
1055 // if there is an error and it isn't EAGAIN|EWOULDBLOCK, return it.
1056 // if it is EAGAIN|EWOULDBLOCK return it only if nothing was transferred.
1057 if (ec &&
1058 ((ec != make_error_condition(std::errc::resource_unavailable_try_again) &&
1059 ec != make_error_condition(std::errc::operation_would_block)) ||
1060 transferred == 0)) {
1061 return stdx::make_unexpected(ec);
1062 } else {
1063 return transferred;
1064 }
1065}
1066
1067// 17.8 [buffer.async.write]
1068
1069template <class AsyncWriteStream, class DynamicBuffer,
1070 class CompletionCondition, class CompletionToken>
1071std::enable_if_t<is_dynamic_buffer<DynamicBuffer>::value, void> async_write(
1072 AsyncWriteStream &stream, DynamicBuffer &&b, CompletionCondition cond,
1073 CompletionToken &&token) {
1074 async_completion<CompletionToken, void(std::error_code, size_t)> init{token};
1075
1076 using compl_handler_type = typename decltype(init)::completion_handler_type;
1077
1078 class Completor {
1079 public:
1080 Completor(AsyncWriteStream &stream, DynamicBuffer &&b,
1081 CompletionCondition cond, compl_handler_type &&compl_handler)
1082 : stream_{stream},
1083 b_{std::forward<DynamicBuffer>(b)},
1084 cond_{cond},
1085 compl_handler_(std::forward<compl_handler_type>(compl_handler)) {}
1086
1087 Completor(const Completor &) = delete;
1088 Completor(Completor &&) = default;
1089
1090 void operator()(std::error_code ec) {
1091 if (ec) {
1092 compl_handler_(ec, 0);
1093 return;
1094 }
1095
1096 const auto res =
1097 net::write(stream_, std::forward<DynamicBuffer>(b_), cond_);
1098
1099 if (!res) {
1100 compl_handler_(res.error(), 0);
1101 } else {
1102 compl_handler_({}, res.value());
1103 }
1104
1105 return;
1106 }
1107
1108 private:
1109 AsyncWriteStream &stream_;
1110 DynamicBuffer b_;
1111 CompletionCondition cond_;
1112 compl_handler_type compl_handler_;
1113 };
1114
1116 Completor(stream, std::forward<DynamicBuffer>(b), cond,
1117 std::move(init.completion_handler)));
1118
1119 return init.result.get();
1120}
1121template <class AsyncWriteStream, class DynamicBuffer, class CompletionToken>
1122std::enable_if_t<is_dynamic_buffer<DynamicBuffer>::value, void> async_write(
1123 AsyncWriteStream &stream, DynamicBuffer &&b, CompletionToken &&token) {
1124 return async_write(stream, std::forward<DynamicBuffer>(b),
1125 net::transfer_all(), std::forward<CompletionToken>(token));
1126}
1127
1128// 17.9 [buffer.read.until] not-implemented-ye
1129
1130// 17.10 [buffer.async.read.until] not-implemented-yet
1131
1132} // namespace net
1133
1134#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:775
size_t total_consumed() const
Definition: buffer.h:823
void consume(size_t n)
mark bytes as consumed from the beginning of the unconsumed sequence.
Definition: buffer.h:820
const BufferSequence & buffers_
Definition: buffer.h:826
consuming_buffers(const BufferSequence &buffers)
Definition: buffer.h:779
prepared_buffer_type prepare(size_t max_size)
prepare a buffer sequence, skipping the already consumed bytes.
Definition: buffer.h:788
size_t total_consumed_
Definition: buffer.h:827
Definition: buffer.h:651
Definition: buffer.h:641
Definition: buffer.h:563
T & v_
Definition: buffer.h:631
const_buffers_type data(size_t pos, size_t n) const noexcept
Definition: buffer.h:590
size_t max_size() const noexcept
max number of bytes.
Definition: buffer.h:581
void grow(size_t n)
append bytes at the end.
Definition: buffer.h:601
dynamic_buffer_base(T &v) noexcept
Definition: buffer.h:568
void consume(size_t n)
remove bytes at the start.
Definition: buffer.h:621
dynamic_buffer_base(T &v, size_t max_size) noexcept
Definition: buffer.h:570
void shrink(size_t n)
remove bytes at the end.
Definition: buffer.h:611
mutable_buffers_type data(size_t pos, size_t n)
Definition: buffer.h:594
const size_t max_size_
Definition: buffer.h:632
size_t size() const noexcept
number of bytes.
Definition: buffer.h:576
size_t capacity() const noexcept
max number of bytes without requiring reallocation.
Definition: buffer.h:586
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:733
const_iterator begin() const
Definition: buffer.h:746
typename storage_type::iterator iterator
Definition: buffer.h:744
BufferType value_type
Definition: buffer.h:735
constexpr size_t max_size() const noexcept
Definition: buffer.h:759
size_t used_
Definition: buffer.h:763
typename storage_type::const_iterator const_iterator
Definition: buffer.h:743
void push_back(value_type &&v)
Definition: buffer.h:749
size_t size() const noexcept
Definition: buffer.h:757
std::array< BufferType, 16 > storage_type
Definition: buffer.h:742
const_iterator end() const
Definition: buffer.h:747
storage_type bufs_
Definition: buffer.h:762
Definition: buffer.h:685
size_t operator()(const std::error_code &ec, size_t) const
Definition: buffer.h:687
Definition: buffer.h:695
size_t minimum_
Definition: buffer.h:706
size_t operator()(const std::error_code &ec, size_t n) const
Definition: buffer.h:699
transfer_at_least(size_t m)
Definition: buffer.h:697
Definition: buffer.h:711
transfer_exactly(size_t m)
Definition: buffer.h:713
size_t exact_
Definition: buffer.h:728
size_t operator()(const std::error_code &ec, size_t n) const
Definition: buffer.h:718
Definition: span.h:264
const char * p
Definition: ctype-mb.cc:1234
bool equivalent(const MDL_ticket *a, const MDL_ticket *b, enum_mdl_duration target_duration)
Definition: mdl.cc:2614
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:1085
Definition: authentication.cc:35
mutable_buffer to_mutable_buffer(T *data, size_t n)
Definition: buffer.h:432
const_buffer to_const_buffer(const T *data, size_t n)
Definition: buffer.h:437
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:234
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:331
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:660
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:989
mutable_buffer buffer(void *p, size_t n) noexcept
Definition: buffer.h:417
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:925
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:348
size_t buffer_size(const ConstBufferSequence &buffers) noexcept
Definition: buffer.h:312
size_t buffer_size< const_buffer >(const const_buffer &b) noexcept
Definition: buffer.h:326
mutable_buffer operator+(const mutable_buffer &b, size_t n) noexcept
Definition: buffer.h:397
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:835
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:1071
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:237
Definition: buffer.h:246
Definition: buffer.h:262
Definition: buffer.h:258
Definition: buffer.h:307
Definition: buffer.h:255
Definition: dtoa.cc:588
int n
Definition: xcom_base.cc:508