Skip to content

Commit

Permalink
Allow buffers to be implicitly constructed from spans.
Browse files Browse the repository at this point in the history
  • Loading branch information
chriskohlhoff committed Oct 23, 2024
1 parent 54d9070 commit 9b6f60e
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 11 deletions.
89 changes: 89 additions & 0 deletions asio/include/asio/buffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,43 @@
#include "asio/detail/push_options.hpp"

namespace asio {
namespace detail {

#if defined(ASIO_MSVC)

struct span_memfns_base
{
void subspan();
};

template <typename T>
struct span_memfns_derived : T, span_memfns_base
{
};

template <typename T, T>
struct span_memfns_check
{
};

template <typename>
char (&subspan_memfn_helper(...))[2];

template <typename T>
char subspan_memfn_helper(
span_memfns_check<
void (span_memfns_base::*)(),
&span_memfns_derived<T>::subspan>*);

template <typename T>
struct has_subspan_memfn :
integral_constant<bool, sizeof(subspan_memfn_helper<T>(0)) != 1>
{
};

#endif // defined(ASIO_MSVC)

} // namespace detail

class mutable_buffer;
class const_buffer;
Expand Down Expand Up @@ -92,6 +129,34 @@ class mutable_buffer
{
}

/// Construct a buffer from a span of bytes.
template <template <typename, std::size_t> class Span,
typename T, std::size_t Extent>
mutable_buffer(const Span<T, Extent>& span,
constraint_t<
!is_const<T>::value,
defaulted_constraint
> = defaulted_constraint(),
constraint_t<
sizeof(T) == 1,
defaulted_constraint
> = defaulted_constraint(),
constraint_t<
#if defined(ASIO_MSVC)
detail::has_subspan_memfn<Span<T, Extent>>::value,
#else // defined(ASIO_MSVC)
is_same<
decltype(span.subspan(0, 0)),
Span<T, static_cast<std::size_t>(-1)>
>::value,
#endif // defined(ASIO_MSVC)
defaulted_constraint
> = defaulted_constraint())
: data_(span.data()),
size_(span.size())
{
}

#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
mutable_buffer(void* data, std::size_t size,
asio::detail::function<void()> debug_check)
Expand Down Expand Up @@ -187,6 +252,30 @@ class const_buffer
{
}

/// Construct a buffer from a span of bytes.
template <template <typename, std::size_t> class Span,
typename T, std::size_t Extent>
const_buffer(const Span<T, Extent>& span,
constraint_t<
sizeof(T) == 1,
defaulted_constraint
> = defaulted_constraint(),
constraint_t<
#if defined(ASIO_MSVC)
detail::has_subspan_memfn<Span<T, Extent>>::value,
#else // defined(ASIO_MSVC)
is_same<
decltype(span.subspan(0, 0)),
Span<T, static_cast<std::size_t>(-1)>
>::value,
#endif // defined(ASIO_MSVC)
defaulted_constraint
> = defaulted_constraint())
: data_(span.data()),
size_(span.size())
{
}

#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
const_buffer(const void* data, std::size_t size,
asio::detail::function<void()> debug_check)
Expand Down
49 changes: 38 additions & 11 deletions asio/src/tests/unit/buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,25 @@ class const_contiguous_container
const_iterator end() const { return 0; }
};

template <typename T, std::size_t Extent>
struct span
{
T* data() const { return 0; }
std::size_t size() const { return 0; }
friend span<const T, Extent> as_bytes(const span&) { return {}; }
span<T, static_cast<std::size_t>(-1)>
subspan(std::size_t, std::size_t = 0) const { return {}; }
};

template <typename T, std::size_t Extent>
struct span<const T, Extent>
{
T* data() const { return 0; }
std::size_t size() const { return 0; }
span<const T, static_cast<std::size_t>(-1)>
subspan(std::size_t, std::size_t = 0) const { return {}; }
};

void test()
{
try
Expand All @@ -79,6 +98,8 @@ void test()
const char const_raw_data[1024] = "";
void* void_ptr_data = raw_data;
const void* const_void_ptr_data = const_raw_data;
span<char, 1> span_1;
span<const char, 1> span_2;
#if defined(ASIO_HAS_BOOST_ARRAY)
boost::array<char, 1024> array_data;
const boost::array<char, 1024>& const_array_data_1 = array_data;
Expand Down Expand Up @@ -107,8 +128,10 @@ void test()

mutable_buffer mb1;
mutable_buffer mb2(void_ptr_data, 1024);
mutable_buffer mb3(mb1);
mutable_buffer mb3(span_1);
(void)mb3;
mutable_buffer mb4(mb1);
(void)mb4;

// mutable_buffer functions.

Expand All @@ -128,10 +151,14 @@ void test()

const_buffer cb1;
const_buffer cb2(const_void_ptr_data, 1024);
const_buffer cb3(cb1);
const_buffer cb3(span_1);
(void)cb3;
const_buffer cb4(mb1);
const_buffer cb4(span_2);
(void)cb4;
const_buffer cb5(cb1);
(void)cb5;
const_buffer cb6(mb1);
(void)cb6;

// const_buffer functions.

Expand Down Expand Up @@ -264,11 +291,11 @@ void test()
#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)
dynamic_string_buffer<char, std::string::traits_type,
std::string::allocator_type>::const_buffers_type
cb5 = db1.data();
(void)cb5;
cb7 = db1.data();
(void)cb7;
dynamic_vector_buffer<char, std::allocator<char> >::const_buffers_type
cb6 = db3.data();
(void)cb6;
cb8 = db3.data();
(void)cb8;

dynamic_string_buffer<char, std::string::traits_type,
std::string::allocator_type>::mutable_buffers_type mb5
Expand All @@ -292,14 +319,14 @@ void test()

dynamic_string_buffer<char, std::string::traits_type,
std::string::allocator_type>::const_buffers_type
cb7 = static_cast<const dynamic_string_buffer<char,
cb9 = static_cast<const dynamic_string_buffer<char,
std::string::traits_type,
std::string::allocator_type>&>(db1).data(0, 1);
(void)cb7;
(void)cb9;
dynamic_vector_buffer<char, std::allocator<char> >::const_buffers_type
cb8 = static_cast<const dynamic_vector_buffer<char,
cb10 = static_cast<const dynamic_vector_buffer<char,
std::allocator<char> >&>(db3).data(0, 1);
(void)cb8;
(void)cb10;

db1.grow(1024);
db3.grow(1024);
Expand Down

0 comments on commit 9b6f60e

Please sign in to comment.