1 // 2 // detail/buffer_sequence_adapter.hpp 3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 // 7 // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 // 10 11 #ifndef BOOST_ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP 12 #define BOOST_ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP 13 14 #if defined(_MSC_VER) && (_MSC_VER >= 1200) 15 # pragma once 16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 17 18 #include <boost/asio/detail/config.hpp> 19 #include <boost/asio/buffer.hpp> 20 #include <boost/asio/detail/array_fwd.hpp> 21 #include <boost/asio/detail/socket_types.hpp> 22 23 #include <boost/asio/detail/push_options.hpp> 24 25 namespace boost { 26 namespace asio { 27 namespace detail { 28 29 class buffer_sequence_adapter_base 30 { 31 #if defined(BOOST_ASIO_WINDOWS_RUNTIME) 32 public: 33 // The maximum number of buffers to support in a single operation. 34 enum { max_buffers = 1 }; 35 36 protected: 37 typedef Windows::Storage::Streams::IBuffer^ native_buffer_type; 38 39 BOOST_ASIO_DECL static void init_native_buffer( 40 native_buffer_type& buf, 41 const boost::asio::mutable_buffer& buffer); 42 43 BOOST_ASIO_DECL static void init_native_buffer( 44 native_buffer_type& buf, 45 const boost::asio::const_buffer& buffer); 46 #elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) 47 public: 48 // The maximum number of buffers to support in a single operation. 49 enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; 50 51 protected: 52 typedef WSABUF native_buffer_type; 53 54 static void init_native_buffer(WSABUF& buf, 55 const boost::asio::mutable_buffer& buffer) 56 { 57 buf.buf = static_cast<char*>(buffer.data()); 58 buf.len = static_cast<ULONG>(buffer.size()); 59 } 60 61 static void init_native_buffer(WSABUF& buf, 62 const boost::asio::const_buffer& buffer) 63 { 64 buf.buf = const_cast<char*>(static_cast<const char*>(buffer.data())); 65 buf.len = static_cast<ULONG>(buffer.size()); 66 } 67 #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) 68 public: 69 // The maximum number of buffers to support in a single operation. 70 enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; 71 72 protected: 73 typedef iovec native_buffer_type; 74 75 static void init_iov_base(void*& base, void* addr) 76 { 77 base = addr; 78 } 79 80 template <typename T> 81 static void init_iov_base(T& base, void* addr) 82 { 83 base = static_cast<T>(addr); 84 } 85 86 static void init_native_buffer(iovec& iov, 87 const boost::asio::mutable_buffer& buffer) 88 { 89 init_iov_base(iov.iov_base, buffer.data()); 90 iov.iov_len = buffer.size(); 91 } 92 93 static void init_native_buffer(iovec& iov, 94 const boost::asio::const_buffer& buffer) 95 { 96 init_iov_base(iov.iov_base, const_cast<void*>(buffer.data())); 97 iov.iov_len = buffer.size(); 98 } 99 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) 100 }; 101 102 // Helper class to translate buffers into the native buffer representation. 103 template <typename Buffer, typename Buffers> 104 class buffer_sequence_adapter 105 : buffer_sequence_adapter_base 106 { 107 public: 108 enum { is_single_buffer = false }; 109 buffer_sequence_adapter(const Buffers & buffer_sequence)110 explicit buffer_sequence_adapter(const Buffers& buffer_sequence) 111 : count_(0), total_buffer_size_(0) 112 { 113 buffer_sequence_adapter::init( 114 boost::asio::buffer_sequence_begin(buffer_sequence), 115 boost::asio::buffer_sequence_end(buffer_sequence)); 116 } 117 buffers()118 native_buffer_type* buffers() 119 { 120 return buffers_; 121 } 122 count() const123 std::size_t count() const 124 { 125 return count_; 126 } 127 total_size() const128 std::size_t total_size() const 129 { 130 return total_buffer_size_; 131 } 132 all_empty() const133 bool all_empty() const 134 { 135 return total_buffer_size_ == 0; 136 } 137 all_empty(const Buffers & buffer_sequence)138 static bool all_empty(const Buffers& buffer_sequence) 139 { 140 return buffer_sequence_adapter::all_empty( 141 boost::asio::buffer_sequence_begin(buffer_sequence), 142 boost::asio::buffer_sequence_end(buffer_sequence)); 143 } 144 validate(const Buffers & buffer_sequence)145 static void validate(const Buffers& buffer_sequence) 146 { 147 buffer_sequence_adapter::validate( 148 boost::asio::buffer_sequence_begin(buffer_sequence), 149 boost::asio::buffer_sequence_end(buffer_sequence)); 150 } 151 first(const Buffers & buffer_sequence)152 static Buffer first(const Buffers& buffer_sequence) 153 { 154 return buffer_sequence_adapter::first( 155 boost::asio::buffer_sequence_begin(buffer_sequence), 156 boost::asio::buffer_sequence_end(buffer_sequence)); 157 } 158 159 enum { linearisation_storage_size = 8192 }; 160 linearise(const Buffers & buffer_sequence,const boost::asio::mutable_buffer & storage)161 static Buffer linearise(const Buffers& buffer_sequence, 162 const boost::asio::mutable_buffer& storage) 163 { 164 return buffer_sequence_adapter::linearise( 165 boost::asio::buffer_sequence_begin(buffer_sequence), 166 boost::asio::buffer_sequence_end(buffer_sequence), storage); 167 } 168 169 private: 170 template <typename Iterator> init(Iterator begin,Iterator end)171 void init(Iterator begin, Iterator end) 172 { 173 Iterator iter = begin; 174 for (; iter != end && count_ < max_buffers; ++iter, ++count_) 175 { 176 Buffer buffer(*iter); 177 init_native_buffer(buffers_[count_], buffer); 178 total_buffer_size_ += buffer.size(); 179 } 180 } 181 182 template <typename Iterator> all_empty(Iterator begin,Iterator end)183 static bool all_empty(Iterator begin, Iterator end) 184 { 185 Iterator iter = begin; 186 std::size_t i = 0; 187 for (; iter != end && i < max_buffers; ++iter, ++i) 188 if (Buffer(*iter).size() > 0) 189 return false; 190 return true; 191 } 192 193 template <typename Iterator> validate(Iterator begin,Iterator end)194 static void validate(Iterator begin, Iterator end) 195 { 196 Iterator iter = begin; 197 for (; iter != end; ++iter) 198 { 199 Buffer buffer(*iter); 200 buffer.data(); 201 } 202 } 203 204 template <typename Iterator> first(Iterator begin,Iterator end)205 static Buffer first(Iterator begin, Iterator end) 206 { 207 Iterator iter = begin; 208 for (; iter != end; ++iter) 209 { 210 Buffer buffer(*iter); 211 if (buffer.size() != 0) 212 return buffer; 213 } 214 return Buffer(); 215 } 216 217 template <typename Iterator> linearise(Iterator begin,Iterator end,const boost::asio::mutable_buffer & storage)218 static Buffer linearise(Iterator begin, Iterator end, 219 const boost::asio::mutable_buffer& storage) 220 { 221 boost::asio::mutable_buffer unused_storage = storage; 222 Iterator iter = begin; 223 while (iter != end && unused_storage.size() != 0) 224 { 225 Buffer buffer(*iter); 226 ++iter; 227 if (buffer.size() == 0) 228 continue; 229 if (unused_storage.size() == storage.size()) 230 { 231 if (iter == end) 232 return buffer; 233 if (buffer.size() >= unused_storage.size()) 234 return buffer; 235 } 236 unused_storage += boost::asio::buffer_copy(unused_storage, buffer); 237 } 238 return Buffer(storage.data(), storage.size() - unused_storage.size()); 239 } 240 241 native_buffer_type buffers_[max_buffers]; 242 std::size_t count_; 243 std::size_t total_buffer_size_; 244 }; 245 246 template <typename Buffer> 247 class buffer_sequence_adapter<Buffer, boost::asio::mutable_buffer> 248 : buffer_sequence_adapter_base 249 { 250 public: 251 enum { is_single_buffer = true }; 252 buffer_sequence_adapter(const boost::asio::mutable_buffer & buffer_sequence)253 explicit buffer_sequence_adapter( 254 const boost::asio::mutable_buffer& buffer_sequence) 255 { 256 init_native_buffer(buffer_, Buffer(buffer_sequence)); 257 total_buffer_size_ = buffer_sequence.size(); 258 } 259 buffers()260 native_buffer_type* buffers() 261 { 262 return &buffer_; 263 } 264 count() const265 std::size_t count() const 266 { 267 return 1; 268 } 269 total_size() const270 std::size_t total_size() const 271 { 272 return total_buffer_size_; 273 } 274 all_empty() const275 bool all_empty() const 276 { 277 return total_buffer_size_ == 0; 278 } 279 all_empty(const boost::asio::mutable_buffer & buffer_sequence)280 static bool all_empty(const boost::asio::mutable_buffer& buffer_sequence) 281 { 282 return buffer_sequence.size() == 0; 283 } 284 validate(const boost::asio::mutable_buffer & buffer_sequence)285 static void validate(const boost::asio::mutable_buffer& buffer_sequence) 286 { 287 buffer_sequence.data(); 288 } 289 first(const boost::asio::mutable_buffer & buffer_sequence)290 static Buffer first(const boost::asio::mutable_buffer& buffer_sequence) 291 { 292 return Buffer(buffer_sequence); 293 } 294 295 enum { linearisation_storage_size = 1 }; 296 linearise(const boost::asio::mutable_buffer & buffer_sequence,const Buffer &)297 static Buffer linearise(const boost::asio::mutable_buffer& buffer_sequence, 298 const Buffer&) 299 { 300 return Buffer(buffer_sequence); 301 } 302 303 private: 304 native_buffer_type buffer_; 305 std::size_t total_buffer_size_; 306 }; 307 308 template <typename Buffer> 309 class buffer_sequence_adapter<Buffer, boost::asio::const_buffer> 310 : buffer_sequence_adapter_base 311 { 312 public: 313 enum { is_single_buffer = true }; 314 buffer_sequence_adapter(const boost::asio::const_buffer & buffer_sequence)315 explicit buffer_sequence_adapter( 316 const boost::asio::const_buffer& buffer_sequence) 317 { 318 init_native_buffer(buffer_, Buffer(buffer_sequence)); 319 total_buffer_size_ = buffer_sequence.size(); 320 } 321 buffers()322 native_buffer_type* buffers() 323 { 324 return &buffer_; 325 } 326 count() const327 std::size_t count() const 328 { 329 return 1; 330 } 331 total_size() const332 std::size_t total_size() const 333 { 334 return total_buffer_size_; 335 } 336 all_empty() const337 bool all_empty() const 338 { 339 return total_buffer_size_ == 0; 340 } 341 all_empty(const boost::asio::const_buffer & buffer_sequence)342 static bool all_empty(const boost::asio::const_buffer& buffer_sequence) 343 { 344 return buffer_sequence.size() == 0; 345 } 346 validate(const boost::asio::const_buffer & buffer_sequence)347 static void validate(const boost::asio::const_buffer& buffer_sequence) 348 { 349 buffer_sequence.data(); 350 } 351 first(const boost::asio::const_buffer & buffer_sequence)352 static Buffer first(const boost::asio::const_buffer& buffer_sequence) 353 { 354 return Buffer(buffer_sequence); 355 } 356 357 enum { linearisation_storage_size = 1 }; 358 linearise(const boost::asio::const_buffer & buffer_sequence,const Buffer &)359 static Buffer linearise(const boost::asio::const_buffer& buffer_sequence, 360 const Buffer&) 361 { 362 return Buffer(buffer_sequence); 363 } 364 365 private: 366 native_buffer_type buffer_; 367 std::size_t total_buffer_size_; 368 }; 369 370 #if !defined(BOOST_ASIO_NO_DEPRECATED) 371 372 template <typename Buffer> 373 class buffer_sequence_adapter<Buffer, boost::asio::mutable_buffers_1> 374 : buffer_sequence_adapter_base 375 { 376 public: 377 enum { is_single_buffer = true }; 378 buffer_sequence_adapter(const boost::asio::mutable_buffers_1 & buffer_sequence)379 explicit buffer_sequence_adapter( 380 const boost::asio::mutable_buffers_1& buffer_sequence) 381 { 382 init_native_buffer(buffer_, Buffer(buffer_sequence)); 383 total_buffer_size_ = buffer_sequence.size(); 384 } 385 buffers()386 native_buffer_type* buffers() 387 { 388 return &buffer_; 389 } 390 count() const391 std::size_t count() const 392 { 393 return 1; 394 } 395 total_size() const396 std::size_t total_size() const 397 { 398 return total_buffer_size_; 399 } 400 all_empty() const401 bool all_empty() const 402 { 403 return total_buffer_size_ == 0; 404 } 405 all_empty(const boost::asio::mutable_buffers_1 & buffer_sequence)406 static bool all_empty(const boost::asio::mutable_buffers_1& buffer_sequence) 407 { 408 return buffer_sequence.size() == 0; 409 } 410 validate(const boost::asio::mutable_buffers_1 & buffer_sequence)411 static void validate(const boost::asio::mutable_buffers_1& buffer_sequence) 412 { 413 buffer_sequence.data(); 414 } 415 first(const boost::asio::mutable_buffers_1 & buffer_sequence)416 static Buffer first(const boost::asio::mutable_buffers_1& buffer_sequence) 417 { 418 return Buffer(buffer_sequence); 419 } 420 421 enum { linearisation_storage_size = 1 }; 422 linearise(const boost::asio::mutable_buffers_1 & buffer_sequence,const Buffer &)423 static Buffer linearise(const boost::asio::mutable_buffers_1& buffer_sequence, 424 const Buffer&) 425 { 426 return Buffer(buffer_sequence); 427 } 428 429 private: 430 native_buffer_type buffer_; 431 std::size_t total_buffer_size_; 432 }; 433 434 template <typename Buffer> 435 class buffer_sequence_adapter<Buffer, boost::asio::const_buffers_1> 436 : buffer_sequence_adapter_base 437 { 438 public: 439 enum { is_single_buffer = true }; 440 buffer_sequence_adapter(const boost::asio::const_buffers_1 & buffer_sequence)441 explicit buffer_sequence_adapter( 442 const boost::asio::const_buffers_1& buffer_sequence) 443 { 444 init_native_buffer(buffer_, Buffer(buffer_sequence)); 445 total_buffer_size_ = buffer_sequence.size(); 446 } 447 buffers()448 native_buffer_type* buffers() 449 { 450 return &buffer_; 451 } 452 count() const453 std::size_t count() const 454 { 455 return 1; 456 } 457 total_size() const458 std::size_t total_size() const 459 { 460 return total_buffer_size_; 461 } 462 all_empty() const463 bool all_empty() const 464 { 465 return total_buffer_size_ == 0; 466 } 467 all_empty(const boost::asio::const_buffers_1 & buffer_sequence)468 static bool all_empty(const boost::asio::const_buffers_1& buffer_sequence) 469 { 470 return buffer_sequence.size() == 0; 471 } 472 validate(const boost::asio::const_buffers_1 & buffer_sequence)473 static void validate(const boost::asio::const_buffers_1& buffer_sequence) 474 { 475 buffer_sequence.data(); 476 } 477 first(const boost::asio::const_buffers_1 & buffer_sequence)478 static Buffer first(const boost::asio::const_buffers_1& buffer_sequence) 479 { 480 return Buffer(buffer_sequence); 481 } 482 483 enum { linearisation_storage_size = 1 }; 484 linearise(const boost::asio::const_buffers_1 & buffer_sequence,const Buffer &)485 static Buffer linearise(const boost::asio::const_buffers_1& buffer_sequence, 486 const Buffer&) 487 { 488 return Buffer(buffer_sequence); 489 } 490 491 private: 492 native_buffer_type buffer_; 493 std::size_t total_buffer_size_; 494 }; 495 496 #endif // !defined(BOOST_ASIO_NO_DEPRECATED) 497 498 template <typename Buffer, typename Elem> 499 class buffer_sequence_adapter<Buffer, boost::array<Elem, 2> > 500 : buffer_sequence_adapter_base 501 { 502 public: 503 enum { is_single_buffer = false }; 504 buffer_sequence_adapter(const boost::array<Elem,2> & buffer_sequence)505 explicit buffer_sequence_adapter( 506 const boost::array<Elem, 2>& buffer_sequence) 507 { 508 init_native_buffer(buffers_[0], Buffer(buffer_sequence[0])); 509 init_native_buffer(buffers_[1], Buffer(buffer_sequence[1])); 510 total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size(); 511 } 512 buffers()513 native_buffer_type* buffers() 514 { 515 return buffers_; 516 } 517 count() const518 std::size_t count() const 519 { 520 return 2; 521 } 522 total_size() const523 std::size_t total_size() const 524 { 525 return total_buffer_size_; 526 } 527 all_empty() const528 bool all_empty() const 529 { 530 return total_buffer_size_ == 0; 531 } 532 all_empty(const boost::array<Elem,2> & buffer_sequence)533 static bool all_empty(const boost::array<Elem, 2>& buffer_sequence) 534 { 535 return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0; 536 } 537 validate(const boost::array<Elem,2> & buffer_sequence)538 static void validate(const boost::array<Elem, 2>& buffer_sequence) 539 { 540 buffer_sequence[0].data(); 541 buffer_sequence[1].data(); 542 } 543 first(const boost::array<Elem,2> & buffer_sequence)544 static Buffer first(const boost::array<Elem, 2>& buffer_sequence) 545 { 546 return Buffer(buffer_sequence[0].size() != 0 547 ? buffer_sequence[0] : buffer_sequence[1]); 548 } 549 550 enum { linearisation_storage_size = 8192 }; 551 linearise(const boost::array<Elem,2> & buffer_sequence,const boost::asio::mutable_buffer & storage)552 static Buffer linearise(const boost::array<Elem, 2>& buffer_sequence, 553 const boost::asio::mutable_buffer& storage) 554 { 555 if (buffer_sequence[0].size() == 0) 556 return Buffer(buffer_sequence[1]); 557 if (buffer_sequence[1].size() == 0) 558 return Buffer(buffer_sequence[0]); 559 return Buffer(storage.data(), 560 boost::asio::buffer_copy(storage, buffer_sequence)); 561 } 562 563 private: 564 native_buffer_type buffers_[2]; 565 std::size_t total_buffer_size_; 566 }; 567 568 #if defined(BOOST_ASIO_HAS_STD_ARRAY) 569 570 template <typename Buffer, typename Elem> 571 class buffer_sequence_adapter<Buffer, std::array<Elem, 2> > 572 : buffer_sequence_adapter_base 573 { 574 public: 575 enum { is_single_buffer = false }; 576 buffer_sequence_adapter(const std::array<Elem,2> & buffer_sequence)577 explicit buffer_sequence_adapter( 578 const std::array<Elem, 2>& buffer_sequence) 579 { 580 init_native_buffer(buffers_[0], Buffer(buffer_sequence[0])); 581 init_native_buffer(buffers_[1], Buffer(buffer_sequence[1])); 582 total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size(); 583 } 584 buffers()585 native_buffer_type* buffers() 586 { 587 return buffers_; 588 } 589 count() const590 std::size_t count() const 591 { 592 return 2; 593 } 594 total_size() const595 std::size_t total_size() const 596 { 597 return total_buffer_size_; 598 } 599 all_empty() const600 bool all_empty() const 601 { 602 return total_buffer_size_ == 0; 603 } 604 all_empty(const std::array<Elem,2> & buffer_sequence)605 static bool all_empty(const std::array<Elem, 2>& buffer_sequence) 606 { 607 return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0; 608 } 609 validate(const std::array<Elem,2> & buffer_sequence)610 static void validate(const std::array<Elem, 2>& buffer_sequence) 611 { 612 buffer_sequence[0].data(); 613 buffer_sequence[1].data(); 614 } 615 first(const std::array<Elem,2> & buffer_sequence)616 static Buffer first(const std::array<Elem, 2>& buffer_sequence) 617 { 618 return Buffer(buffer_sequence[0].size() != 0 619 ? buffer_sequence[0] : buffer_sequence[1]); 620 } 621 622 enum { linearisation_storage_size = 8192 }; 623 linearise(const std::array<Elem,2> & buffer_sequence,const boost::asio::mutable_buffer & storage)624 static Buffer linearise(const std::array<Elem, 2>& buffer_sequence, 625 const boost::asio::mutable_buffer& storage) 626 { 627 if (buffer_sequence[0].size() == 0) 628 return Buffer(buffer_sequence[1]); 629 if (buffer_sequence[1].size() == 0) 630 return Buffer(buffer_sequence[0]); 631 return Buffer(storage.data(), 632 boost::asio::buffer_copy(storage, buffer_sequence)); 633 } 634 635 private: 636 native_buffer_type buffers_[2]; 637 std::size_t total_buffer_size_; 638 }; 639 640 #endif // defined(BOOST_ASIO_HAS_STD_ARRAY) 641 642 } // namespace detail 643 } // namespace asio 644 } // namespace boost 645 646 #include <boost/asio/detail/pop_options.hpp> 647 648 #if defined(BOOST_ASIO_HEADER_ONLY) 649 # include <boost/asio/detail/impl/buffer_sequence_adapter.ipp> 650 #endif // defined(BOOST_ASIO_HEADER_ONLY) 651 652 #endif // BOOST_ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP 653