123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- // Copyright Takatoshi Kondo 2019
- //
- // Distributed under the Boost Software License, Version 1.0.
- // (See accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- #if !defined(MQTT_BUFFER_HPP)
- #define MQTT_BUFFER_HPP
- #include <stdexcept>
- #include <utility>
- #include <type_traits>
- #include <boost/asio/buffer.hpp>
- #include <mqtt/namespace.hpp>
- #include <mqtt/string_view.hpp>
- #include <mqtt/shared_ptr_array.hpp>
- #include <mqtt/move.hpp>
- namespace MQTT_NS {
- namespace as = boost::asio;
- /**
- * @brief buffer that has string_view interface
- * This class provides string_view interface.
- * This class hold string_view target's lifetime optionally.
- */
- class buffer : public string_view {
- public:
- /**
- * @brief string_view constructor
- * @param sv string_view
- * This constructor doesn't hold the sv target's lifetime.
- * It behaves as string_view. Caller needs to manage the target lifetime.
- */
- explicit constexpr buffer(string_view sv = string_view())
- : string_view(force_move(sv)) {}
- /**
- * @brief string constructor (deleted)
- * @param string
- * This constructor is intentionally deleted.
- * Consider `buffer(std::string("ABC"))`, the buffer points to dangling reference.
- */
- explicit buffer(std::string) = delete; // to avoid misuse
- /**
- * @brief string_view and lifetime constructor
- * @param sv string_view
- * @param spa shared_ptr_array that holds sv target's lifetime
- * If user creates buffer via this constructor, spa's lifetime is held by the buffer.
- */
- buffer(string_view sv, const_shared_ptr_array spa)
- : string_view(force_move(sv)),
- lifetime_(force_move(spa)) {
- }
- /**
- * @brief get substring
- * The returned buffer ragnge is the same as std::string_view::substr().
- * In addition the lifetime is shared between returned buffer and this buffer.
- * @param offset offset point of the buffer
- * @param length length of the buffer, If the length is string_view::npos
- * then the length is from offset to the end of string.
- */
- buffer substr(std::size_t offset, std::size_t length = string_view::npos) const& {
- // range is checked in string_view::substr.
- return buffer(string_view::substr(offset, length), lifetime_);
- }
- /**
- * @brief get substring
- * The returned buffer ragnge is the same as std::string_view::substr().
- * In addition the lifetime is moved to returned buffer.
- * @param offset offset point of the buffer
- * @param length length of the buffer, If the length is string_view::npos
- * then the length is from offset to the end of string.
- */
- buffer substr(std::size_t offset, std::size_t length = string_view::npos) && {
- // range is checked in string_view::substr.
- return buffer(string_view::substr(offset, length), force_move(lifetime_));
- }
- /**
- * @brief check the buffer has lifetime.
- * @return true the buffer has lifetime.
- * false the buffer doesn't have lifetime, This means the buffer is a pure view.
- */
- bool has_life() const {
- return lifetime_.get();
- }
- private:
- const_shared_ptr_array lifetime_;
- };
- inline namespace literals {
- /**
- * @brief user defined literals for buffer
- * If user use this out of mqtt scope, then user need to declare
- * `using namespace literals`.
- * When user write "ABC"_mb, then this function is called.
- * The created buffer doesn't hold any lifetimes because the string literals
- * has static strage duration, so buffer doesn't need to hold the lifetime.
- *
- * @param str the address of the string literal
- * @param length the length of the string literal
- * @return buffer
- */
- inline buffer operator""_mb(char const* str, std::size_t length) {
- return buffer(string_view(str, length));
- }
- } // namespace literals
- /**
- * @brief create buffer from the pair of iterators
- * It copies string that from b to e into shared_ptr_array.
- * Then create buffer and return it.
- * The buffer holds the lifetime of shared_ptr_array.
- *
- * @param b begin position iterator
- * @param e end position iterator
- * @return buffer
- */
- template <typename Iterator>
- inline buffer allocate_buffer(Iterator b, Iterator e) {
- auto size = static_cast<std::size_t>(std::distance(b, e));
- auto spa = make_shared_ptr_array(size);
- std::copy(b, e, spa.get());
- auto view = string_view(spa.get(), size);
- return buffer(view, force_move(spa));
- }
- /**
- * @brief create buffer from the string_view
- * It copies string that from string_view into shared_ptr_array.
- * Then create buffer and return it.
- * The buffer holds the lifetime of shared_ptr_array.
- *
- * @param sv the source string_view
- * @return buffer
- */
- inline buffer allocate_buffer(string_view sv) {
- return allocate_buffer(sv.begin(), sv.end());
- }
- inline buffer const* buffer_sequence_begin(buffer const& buf) {
- return std::addressof(buf);
- }
- inline buffer const* buffer_sequence_end(buffer const& buf) {
- return std::addressof(buf) + 1;
- }
- template <typename Col>
- inline typename Col::const_iterator buffer_sequence_begin(Col const& col) {
- return col.cbegin();
- }
- template <typename Col>
- inline typename Col::const_iterator buffer_sequence_end(Col const& col) {
- return col.cend();
- }
- namespace detail {
- template <typename>
- char buffer_sequence_begin_helper(...);
- template <typename T>
- char (&buffer_sequence_begin_helper(
- T* t,
- typename std::enable_if<
- !std::is_same<
- decltype(buffer_sequence_begin(*t)),
- void
- >::value
- >::type*)
- )[2];
- template <typename>
- char buffer_sequence_end_helper(...);
- template <typename T>
- char (&buffer_sequence_end_helper(
- T* t,
- typename std::enable_if<
- !std::is_same<
- decltype(buffer_sequence_end(*t)),
- void
- >::value
- >::type*)
- )[2];
- template <typename, typename>
- char (&buffer_sequence_element_type_helper(...))[2];
- template <typename T, typename Buffer>
- char buffer_sequence_element_type_helper(
- T* t,
- typename std::enable_if<
- std::is_convertible<
- decltype(*buffer_sequence_begin(*t)),
- Buffer
- >::value
- >::type*
- );
- template <typename T, typename Buffer>
- struct is_buffer_sequence_class
- : std::integral_constant<bool,
- sizeof(buffer_sequence_begin_helper<T>(0, 0)) != 1 &&
- sizeof(buffer_sequence_end_helper<T>(0, 0)) != 1 &&
- sizeof(buffer_sequence_element_type_helper<T, Buffer>(0, 0)) == 1>
- {
- };
- } // namespace detail
- template <typename T>
- struct is_buffer_sequence :
- std::conditional<
- std::is_class<T>::value,
- detail::is_buffer_sequence_class<T, buffer>,
- std::false_type
- >::type
- {
- };
- template <>
- struct is_buffer_sequence<buffer> : std::true_type
- {
- };
- } // namespace MQTT_NS
- namespace boost {
- namespace asio {
- /**
- * @brief create boost::asio::const_buffer from the MQTT_NS::buffer
- * boost::asio::const_buffer is a kind of view class.
- * So the class doesn't hold any lifetimes.
- * The caller needs to manage data's lifetime.
- *
- * @param data source MQTT_NS::buffer
- * @return boost::asio::const_buffer
- */
- inline const_buffer buffer(MQTT_NS::buffer const& data) {
- return buffer(data.data(), data.size());
- }
- } // namespace asio
- } // namespace boost
- #endif // MQTT_BUFFER_HPP
|