asio_utils.h
1 // Copyright 2018, Beeri 15. All rights reserved.
2 // Author: Roman Gershman (romange@gmail.com)
3 //
4 #pragma once
5 
6 #include <array>
7 #include <type_traits>
8 
9 #include <boost/asio/buffer.hpp>
10 #include "base/pod_array.h"
11 
12 namespace boost {
13 namespace asio {
14 
15 inline mutable_buffer buffer(base::PODArray<uint8_t>& arr) noexcept {
16  return mutable_buffer(arr.data(), arr.size());
17 }
18 
19 inline const_buffer buffer(const base::PODArray<uint8_t>& arr) noexcept {
20  return const_buffer(arr.data(), arr.size());
21 }
22 
23 inline mutable_buffer* buffer_sequence_begin(mutable_buffer& b) {
24  return &b;
25 }
26 
28 inline const_buffer* buffer_sequence_begin(const_buffer& b) {
29  return &b;
30 }
31 
32 inline mutable_buffer* buffer_sequence_end(mutable_buffer& b) {
33  return &b + 1;
34 }
35 
37 inline const_buffer* buffer_sequence_end(const_buffer& b) {
38  return &b + 1;
39 }
40 
41 } // namespace asio
42 } // namespace boost
43 
44 namespace util {
45 
46 namespace detail {
47 
48 // Not implemented on purpose since used only in decltype context.
49 template <typename... T>
50 constexpr auto _MakeCommonBuf(T&&... values) ->
51  typename std::common_type<decltype(::boost::asio::buffer(values))...>::type;
52 
53 template <typename BufferSequence>
55  using raw_it_t = decltype(::boost::asio::buffer_sequence_begin(*static_cast<BufferSequence*>(0)));
56  using iterator =
57  std::conditional_t<std::is_pointer<raw_it_t>::value,
58  std::add_pointer_t<std::remove_const_t<std::remove_pointer_t<raw_it_t>>>,
59  raw_it_t>;
60 };
61 
62 static_assert(std::is_same<typename BufferSequenceTraits<::boost::asio::mutable_buffer>::iterator,
63  ::boost::asio::mutable_buffer*>::value,
64  "");
65 
66 static_assert(
67  std::is_same<
68  typename BufferSequenceTraits<::std::vector<::boost::asio::mutable_buffer>>::iterator,
69  ::std::vector<::boost::asio::mutable_buffer>::iterator>::value,
70  "");
71 
72 template <typename It>
73 class Range {
74  public:
75  typedef It iterator;
76 
77  Range() : b_(), e_() {
78  }
79  Range(It b, It e) : b_(b), e_(e) {
80  }
81 
82  It begin() const noexcept {
83  return b_;
84  }
85  It end() const noexcept {
86  return e_;
87  }
88  size_t size() const {
89  return e_ - b_;
90  }
91 
92  private:
93  It b_, e_;
94 };
95 
96 template <typename BufferSequence>
98 
99 } // namespace detail
100 
101 #ifdef __clang__
102 #pragma clang diagnostic push
103 #pragma clang diagnostic ignored "-Wmissing-braces"
104 #endif
105 
106 template <typename... T>
107 constexpr auto make_buffer_seq(T&&... values)
108  -> std::array<decltype(detail::_MakeCommonBuf(values...)), sizeof...(T)> {
109  return {::boost::asio::buffer(values)...};
110 }
111 
112 template <size_t N>
113 constexpr std::array<::boost::asio::mutable_buffer, N + 1> make_buffer_seq(
114  const std::array<::boost::asio::mutable_buffer, N>& arr,
115  const ::boost::asio::mutable_buffer& mbuf) {
116  std::array<::boost::asio::mutable_buffer, N + 1> res;
117  std::copy(arr.begin(), arr.end(), res.begin());
118  res[N] = mbuf;
119  return res;
120 }
121 
122 template <typename It>
123 std::vector<typename std::iterator_traits<It>::value_type> make_buffer_seq(
124  const detail::Range<It>& slice, const typename std::iterator_traits<It>::value_type& mbuf) {
125  using value_type = typename std::iterator_traits<It>::value_type;
126  static_assert(!std::is_const<value_type>::value, "");
127 
128  std::vector<value_type> res(slice.size() + 1);
129  std::copy(slice.begin(), slice.end(), res.begin());
130  res.back() = mbuf;
131  return res;
132 }
133 
134 template <typename BufferSequence>
135 detail::BufferRange<BufferSequence> StripSequence(size_t size, BufferSequence* arg) {
136  using Range = detail::BufferRange<BufferSequence>;
137  using namespace boost::asio;
138 
139  auto b = buffer_sequence_begin(*arg);
140  auto e = buffer_sequence_end(*arg);
141  if (size == 0) {
142  return Range(b, e);
143  }
144 
145  for (; b != e; ++b) {
146  if (b->size() > size) {
147  (*b) += size; // advance the buffer prefix
148  return Range(b, e);
149  }
150  size -= b->size();
151  }
152 
153  return Range();
154 }
155 
156 #ifdef __clang__
157 #pragma clang diagnostic pop
158 #endif
159 
160 } // namespace util