From 8c19aa23ea3291a6e9dc98d6805bcd3565b70ec4 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Sun, 18 Jan 2026 21:18:06 -0800 Subject: [PATCH] Move any_bufref to here --- include/boost/capy/any_bufref.hpp | 129 +++++++++++++++++ test/unit/buffers/any_bufref.cpp | 222 ++++++++++++++++++++++++++++++ 2 files changed, 351 insertions(+) create mode 100644 include/boost/capy/any_bufref.hpp create mode 100644 test/unit/buffers/any_bufref.cpp diff --git a/include/boost/capy/any_bufref.hpp b/include/boost/capy/any_bufref.hpp new file mode 100644 index 0000000..10bd4a0 --- /dev/null +++ b/include/boost/capy/any_bufref.hpp @@ -0,0 +1,129 @@ +// +// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// 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) +// +// Official repository: https://github.com/cppalliance/capy +// + +#ifndef BOOST_CAPY_ANY_BUFREF_HPP +#define BOOST_CAPY_ANY_BUFREF_HPP + +#include +#include + +#include + +namespace boost { +namespace capy { + +/** A type-erased buffer sequence I/O parameter. + + This class provides a type-erased interface for iterating + over buffer sequences without knowing the concrete type. + It allows asynchronous operations to efficiently type-erase + the buffer sequence parameter, avoiding the need to + templatize the implementation. + + @par Example + The following shows the minimal form of an awaitable, templated on the + buffer sequence type, with only an `await_suspend` method. The example + demonstrates that you can construct an `any_bufref` in the parameter + list when calling a virtual interface; there is no need to create a + separate variable if not desired. + + @code + template + struct awaitable + { + Buffers b; + + void await_suspend( std::coroutine_handle<> ) + { + my_virtual_engine_submit( any_bufref( b ) ); + } + }; + + // Example virtual interface accepting any_bufref + void my_virtual_engine_submit( any_bufref p ) + { + capy::mutable_buffer temp[8]; + std::size_t n = p.copy_to( temp, 8 ); + // ... handle the buffers ... + } + @endcode +*/ +class any_bufref +{ +public: + /** Construct from a const buffer sequence. + + @param bs The buffer sequence to adapt. + */ + template + explicit + any_bufref(BS const& bs) noexcept + : bs_(&bs) + , fn_(©_impl) + { + } + + /** Fill an array with buffers from the sequence. + + @param dest Pointer to array of mutable buffer descriptors. + @param n Maximum number of buffers to copy. + + @return The number of buffers actually copied. + */ + std::size_t + copy_to( + mutable_buffer* dest, + std::size_t n) const noexcept + { + return fn_(bs_, dest, n); + } + +private: + template + static std::size_t + copy_impl( + void const* p, + mutable_buffer* dest, + std::size_t n) + { + auto const& bs = *static_cast(p); + auto it = begin(bs); + auto const end_it = end(bs); + + std::size_t i = 0; + if constexpr (MutableBufferSequence) + { + for(; it != end_it && i < n; ++it, ++i) + dest[i] = *it; + } + else + { + for(; it != end_it && i < n; ++it, ++i) + { + auto const& buf = *it; + dest[i] = mutable_buffer( + const_cast( + static_cast(buf.data())), + buf.size()); + } + } + return i; + } + + using fn_t = std::size_t(*)(void const*, + mutable_buffer*, std::size_t); + + void const* bs_; + fn_t fn_; +}; + +} // namespace capy +} // namespace boost + +#endif diff --git a/test/unit/buffers/any_bufref.cpp b/test/unit/buffers/any_bufref.cpp new file mode 100644 index 0000000..8952ff5 --- /dev/null +++ b/test/unit/buffers/any_bufref.cpp @@ -0,0 +1,222 @@ +// +// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// 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) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Test that header file is self-contained. +#include + +#include +#include +#include + +#include "test_buffers.hpp" + +namespace boost { +namespace capy { + +struct any_bufref_test +{ + void + testConstBuffer() + { + char const data[] = "Hello"; + const_buffer cb(data, 5); + + any_bufref ref(cb); + + mutable_buffer dest[8]; + auto n = ref.copy_to(dest, 8); + BOOST_TEST_EQ(n, 1); + BOOST_TEST_EQ(dest[0].data(), data); + BOOST_TEST_EQ(dest[0].size(), 5); + } + + void + testMutableBuffer() + { + char data[] = "Hello"; + mutable_buffer mb(data, 5); + + any_bufref ref(mb); + + mutable_buffer dest[8]; + auto n = ref.copy_to(dest, 8); + BOOST_TEST_EQ(n, 1); + BOOST_TEST_EQ(dest[0].data(), data); + BOOST_TEST_EQ(dest[0].size(), 5); + } + + void + testConstBufferPair() + { + char const data1[] = "Hello"; + char const data2[] = "World"; + const_buffer_pair cbp{{ + const_buffer(data1, 5), + const_buffer(data2, 5) }}; + + any_bufref ref(cbp); + + mutable_buffer dest[8]; + auto n = ref.copy_to(dest, 8); + BOOST_TEST_EQ(n, 2); + BOOST_TEST_EQ(dest[0].data(), data1); + BOOST_TEST_EQ(dest[0].size(), 5); + BOOST_TEST_EQ(dest[1].data(), data2); + BOOST_TEST_EQ(dest[1].size(), 5); + } + + void + testMutableBufferPair() + { + char data1[] = "Hello"; + char data2[] = "World"; + mutable_buffer_pair mbp{{ + mutable_buffer(data1, 5), + mutable_buffer(data2, 5) }}; + + any_bufref ref(mbp); + + mutable_buffer dest[8]; + auto n = ref.copy_to(dest, 8); + BOOST_TEST_EQ(n, 2); + BOOST_TEST_EQ(dest[0].data(), data1); + BOOST_TEST_EQ(dest[0].size(), 5); + BOOST_TEST_EQ(dest[1].data(), data2); + BOOST_TEST_EQ(dest[1].size(), 5); + } + + void + testSpan() + { + char const data1[] = "One"; + char const data2[] = "Two"; + char const data3[] = "Three"; + const_buffer arr[3] = { + const_buffer(data1, 3), + const_buffer(data2, 3), + const_buffer(data3, 5) }; + span s(arr, 3); + + any_bufref ref(s); + + mutable_buffer dest[8]; + auto n = ref.copy_to(dest, 8); + BOOST_TEST_EQ(n, 3); + BOOST_TEST_EQ(dest[0].data(), data1); + BOOST_TEST_EQ(dest[0].size(), 3); + BOOST_TEST_EQ(dest[1].data(), data2); + BOOST_TEST_EQ(dest[1].size(), 3); + BOOST_TEST_EQ(dest[2].data(), data3); + BOOST_TEST_EQ(dest[2].size(), 5); + } + + void + testArray() + { + char const data1[] = "One"; + char const data2[] = "Two"; + char const data3[] = "Three"; + std::array arr{{ + const_buffer(data1, 3), + const_buffer(data2, 3), + const_buffer(data3, 5) }}; + + any_bufref ref(arr); + + mutable_buffer dest[8]; + auto n = ref.copy_to(dest, 8); + BOOST_TEST_EQ(n, 3); + BOOST_TEST_EQ(dest[0].data(), data1); + BOOST_TEST_EQ(dest[0].size(), 3); + BOOST_TEST_EQ(dest[1].data(), data2); + BOOST_TEST_EQ(dest[1].size(), 3); + BOOST_TEST_EQ(dest[2].data(), data3); + BOOST_TEST_EQ(dest[2].size(), 5); + } + + void + testCArray() + { + char const data1[] = "One"; + char const data2[] = "Two"; + char const data3[] = "Three"; + const_buffer arr[3] = { + const_buffer(data1, 3), + const_buffer(data2, 3), + const_buffer(data3, 5) }; + + any_bufref ref(arr); + + mutable_buffer dest[8]; + auto n = ref.copy_to(dest, 8); + BOOST_TEST_EQ(n, 3); + BOOST_TEST_EQ(dest[0].data(), data1); + BOOST_TEST_EQ(dest[0].size(), 3); + BOOST_TEST_EQ(dest[1].data(), data2); + BOOST_TEST_EQ(dest[1].size(), 3); + BOOST_TEST_EQ(dest[2].data(), data3); + BOOST_TEST_EQ(dest[2].size(), 5); + } + + void + testLimitedCopy() + { + char const data1[] = "One"; + char const data2[] = "Two"; + char const data3[] = "Three"; + const_buffer arr[3] = { + const_buffer(data1, 3), + const_buffer(data2, 3), + const_buffer(data3, 5) }; + + any_bufref ref(arr); + + // copy only 2 buffers + mutable_buffer dest[2]; + auto n = ref.copy_to(dest, 2); + BOOST_TEST_EQ(n, 2); + BOOST_TEST_EQ(dest[0].data(), data1); + BOOST_TEST_EQ(dest[0].size(), 3); + BOOST_TEST_EQ(dest[1].data(), data2); + BOOST_TEST_EQ(dest[1].size(), 3); + } + + void + testEmptySequence() + { + const_buffer cb; + any_bufref ref(cb); + + mutable_buffer dest[8]; + auto n = ref.copy_to(dest, 8); + BOOST_TEST_EQ(n, 1); + BOOST_TEST_EQ(dest[0].size(), 0); + } + + void + run() + { + testConstBuffer(); + testMutableBuffer(); + testConstBufferPair(); + testMutableBufferPair(); + testSpan(); + testArray(); + testCArray(); + testLimitedCopy(); + testEmptySequence(); + } +}; + +TEST_SUITE( + any_bufref_test, + "boost.capy.any_bufref"); + +} // capy +} // boost