buffer.hpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. // Copyright Takatoshi Kondo 2019
  2. //
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #if !defined(MQTT_BUFFER_HPP)
  7. #define MQTT_BUFFER_HPP
  8. #include <stdexcept>
  9. #include <utility>
  10. #include <type_traits>
  11. #include <boost/asio/buffer.hpp>
  12. #include <mqtt/namespace.hpp>
  13. #include <mqtt/string_view.hpp>
  14. #include <mqtt/shared_ptr_array.hpp>
  15. #include <mqtt/move.hpp>
  16. namespace MQTT_NS {
  17. namespace as = boost::asio;
  18. /**
  19. * @brief buffer that has string_view interface
  20. * This class provides string_view interface.
  21. * This class hold string_view target's lifetime optionally.
  22. */
  23. class buffer : public string_view {
  24. public:
  25. /**
  26. * @brief string_view constructor
  27. * @param sv string_view
  28. * This constructor doesn't hold the sv target's lifetime.
  29. * It behaves as string_view. Caller needs to manage the target lifetime.
  30. */
  31. explicit constexpr buffer(string_view sv = string_view())
  32. : string_view(force_move(sv)) {}
  33. /**
  34. * @brief string constructor (deleted)
  35. * @param string
  36. * This constructor is intentionally deleted.
  37. * Consider `buffer(std::string("ABC"))`, the buffer points to dangling reference.
  38. */
  39. explicit buffer(std::string) = delete; // to avoid misuse
  40. /**
  41. * @brief string_view and lifetime constructor
  42. * @param sv string_view
  43. * @param spa shared_ptr_array that holds sv target's lifetime
  44. * If user creates buffer via this constructor, spa's lifetime is held by the buffer.
  45. */
  46. buffer(string_view sv, const_shared_ptr_array spa)
  47. : string_view(force_move(sv)),
  48. lifetime_(force_move(spa)) {
  49. }
  50. /**
  51. * @brief get substring
  52. * The returned buffer ragnge is the same as std::string_view::substr().
  53. * In addition the lifetime is shared between returned buffer and this buffer.
  54. * @param offset offset point of the buffer
  55. * @param length length of the buffer, If the length is string_view::npos
  56. * then the length is from offset to the end of string.
  57. */
  58. buffer substr(std::size_t offset, std::size_t length = string_view::npos) const& {
  59. // range is checked in string_view::substr.
  60. return buffer(string_view::substr(offset, length), lifetime_);
  61. }
  62. /**
  63. * @brief get substring
  64. * The returned buffer ragnge is the same as std::string_view::substr().
  65. * In addition the lifetime is moved to returned buffer.
  66. * @param offset offset point of the buffer
  67. * @param length length of the buffer, If the length is string_view::npos
  68. * then the length is from offset to the end of string.
  69. */
  70. buffer substr(std::size_t offset, std::size_t length = string_view::npos) && {
  71. // range is checked in string_view::substr.
  72. return buffer(string_view::substr(offset, length), force_move(lifetime_));
  73. }
  74. /**
  75. * @brief check the buffer has lifetime.
  76. * @return true the buffer has lifetime.
  77. * false the buffer doesn't have lifetime, This means the buffer is a pure view.
  78. */
  79. bool has_life() const {
  80. return lifetime_.get();
  81. }
  82. private:
  83. const_shared_ptr_array lifetime_;
  84. };
  85. inline namespace literals {
  86. /**
  87. * @brief user defined literals for buffer
  88. * If user use this out of mqtt scope, then user need to declare
  89. * `using namespace literals`.
  90. * When user write "ABC"_mb, then this function is called.
  91. * The created buffer doesn't hold any lifetimes because the string literals
  92. * has static strage duration, so buffer doesn't need to hold the lifetime.
  93. *
  94. * @param str the address of the string literal
  95. * @param length the length of the string literal
  96. * @return buffer
  97. */
  98. inline buffer operator""_mb(char const* str, std::size_t length) {
  99. return buffer(string_view(str, length));
  100. }
  101. } // namespace literals
  102. /**
  103. * @brief create buffer from the pair of iterators
  104. * It copies string that from b to e into shared_ptr_array.
  105. * Then create buffer and return it.
  106. * The buffer holds the lifetime of shared_ptr_array.
  107. *
  108. * @param b begin position iterator
  109. * @param e end position iterator
  110. * @return buffer
  111. */
  112. template <typename Iterator>
  113. inline buffer allocate_buffer(Iterator b, Iterator e) {
  114. auto size = static_cast<std::size_t>(std::distance(b, e));
  115. auto spa = make_shared_ptr_array(size);
  116. std::copy(b, e, spa.get());
  117. auto view = string_view(spa.get(), size);
  118. return buffer(view, force_move(spa));
  119. }
  120. /**
  121. * @brief create buffer from the string_view
  122. * It copies string that from string_view into shared_ptr_array.
  123. * Then create buffer and return it.
  124. * The buffer holds the lifetime of shared_ptr_array.
  125. *
  126. * @param sv the source string_view
  127. * @return buffer
  128. */
  129. inline buffer allocate_buffer(string_view sv) {
  130. return allocate_buffer(sv.begin(), sv.end());
  131. }
  132. inline buffer const* buffer_sequence_begin(buffer const& buf) {
  133. return std::addressof(buf);
  134. }
  135. inline buffer const* buffer_sequence_end(buffer const& buf) {
  136. return std::addressof(buf) + 1;
  137. }
  138. template <typename Col>
  139. inline typename Col::const_iterator buffer_sequence_begin(Col const& col) {
  140. return col.cbegin();
  141. }
  142. template <typename Col>
  143. inline typename Col::const_iterator buffer_sequence_end(Col const& col) {
  144. return col.cend();
  145. }
  146. namespace detail {
  147. template <typename>
  148. char buffer_sequence_begin_helper(...);
  149. template <typename T>
  150. char (&buffer_sequence_begin_helper(
  151. T* t,
  152. typename std::enable_if<
  153. !std::is_same<
  154. decltype(buffer_sequence_begin(*t)),
  155. void
  156. >::value
  157. >::type*)
  158. )[2];
  159. template <typename>
  160. char buffer_sequence_end_helper(...);
  161. template <typename T>
  162. char (&buffer_sequence_end_helper(
  163. T* t,
  164. typename std::enable_if<
  165. !std::is_same<
  166. decltype(buffer_sequence_end(*t)),
  167. void
  168. >::value
  169. >::type*)
  170. )[2];
  171. template <typename, typename>
  172. char (&buffer_sequence_element_type_helper(...))[2];
  173. template <typename T, typename Buffer>
  174. char buffer_sequence_element_type_helper(
  175. T* t,
  176. typename std::enable_if<
  177. std::is_convertible<
  178. decltype(*buffer_sequence_begin(*t)),
  179. Buffer
  180. >::value
  181. >::type*
  182. );
  183. template <typename T, typename Buffer>
  184. struct is_buffer_sequence_class
  185. : std::integral_constant<bool,
  186. sizeof(buffer_sequence_begin_helper<T>(0, 0)) != 1 &&
  187. sizeof(buffer_sequence_end_helper<T>(0, 0)) != 1 &&
  188. sizeof(buffer_sequence_element_type_helper<T, Buffer>(0, 0)) == 1>
  189. {
  190. };
  191. } // namespace detail
  192. template <typename T>
  193. struct is_buffer_sequence :
  194. std::conditional<
  195. std::is_class<T>::value,
  196. detail::is_buffer_sequence_class<T, buffer>,
  197. std::false_type
  198. >::type
  199. {
  200. };
  201. template <>
  202. struct is_buffer_sequence<buffer> : std::true_type
  203. {
  204. };
  205. } // namespace MQTT_NS
  206. namespace boost {
  207. namespace asio {
  208. /**
  209. * @brief create boost::asio::const_buffer from the MQTT_NS::buffer
  210. * boost::asio::const_buffer is a kind of view class.
  211. * So the class doesn't hold any lifetimes.
  212. * The caller needs to manage data's lifetime.
  213. *
  214. * @param data source MQTT_NS::buffer
  215. * @return boost::asio::const_buffer
  216. */
  217. inline const_buffer buffer(MQTT_NS::buffer const& data) {
  218. return buffer(data.data(), data.size());
  219. }
  220. } // namespace asio
  221. } // namespace boost
  222. #endif // MQTT_BUFFER_HPP