Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions doc/mrdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ include-symbols:
implementation-defined:
- 'boost::capy::detail'
- 'boost::capy::*::detail'
exclude-symbols:
# Tuple-protocol accessor for structured bindings. Cannot be hidden with an
# in-source BOOST_CAPY_MRDOCS guard because detail::decomposes_to instantiates
# structured bindings on io_result during the docs parse and needs this member.
- 'boost::capy::io_result::get'
inaccessible-members: never
inaccessible-bases: never

Expand Down
82 changes: 56 additions & 26 deletions include/boost/capy/buffers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,12 +198,8 @@ concept MutableBufferSequence =
std::ranges::bidirectional_range<T> &&
std::is_convertible_v<std::ranges::range_value_t<T>, mutable_buffer>);

/** Return an iterator to the first buffer in a sequence.

Handles single buffers and ranges uniformly. For a single buffer,
returns a pointer to it (forming a one-element range).
*/
constexpr struct begin_mrdocs_workaround_t
namespace detail {
struct begin_fn
{
template<std::convertible_to<const_buffer> ConvertibleToBuffer>
auto operator()(ConvertibleToBuffer const& b) const noexcept -> ConvertibleToBuffer const*
Expand All @@ -224,14 +220,22 @@ constexpr struct begin_mrdocs_workaround_t
{
return std::ranges::begin(bs);
}
} begin {};
};
} // detail

/** Return an iterator past the last buffer in a sequence.
/** Return an iterator to the first buffer in a sequence.

Handles single buffers and ranges uniformly. For a single buffer,
returns a pointer one past it.
returns a pointer to it (forming a one-element range).

@param bs The buffer sequence.

@return An iterator to the first buffer in the sequence.
*/
constexpr struct end_mrdocs_workaround_t
constexpr detail::begin_fn begin {};

namespace detail {
struct end_fn
{
template<std::convertible_to<const_buffer> ConvertibleToBuffer>
auto operator()(ConvertibleToBuffer const& b) const noexcept -> ConvertibleToBuffer const*
Expand All @@ -252,20 +256,22 @@ constexpr struct end_mrdocs_workaround_t
{
return std::ranges::end(bs);
}
} end {};
};
} // detail

/** Return the total byte count across all buffers in a sequence.
/** Return an iterator past the last buffer in a sequence.

Sums the `size()` of each buffer in the sequence. This differs
from `buffer_length` which counts the number of buffer elements.
Handles single buffers and ranges uniformly. For a single buffer,
returns a pointer one past it.

@par Example
@code
std::array<mutable_buffer, 2> bufs = { ... };
std::size_t total = buffer_size( bufs ); // sum of both sizes
@endcode
@param bs The buffer sequence.

@return An iterator one past the last buffer in the sequence.
*/
constexpr struct buffer_size_mrdocs_workaround_t
constexpr detail::end_fn end {};

namespace detail {
struct buffer_size_fn
{
// GCC 13 falsely flags reads of arr_[i].n_ in detail::buffer_array
// when iterating here. The class uses union storage with placement
Expand All @@ -290,14 +296,28 @@ constexpr struct buffer_size_mrdocs_workaround_t
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
} buffer_size {};
};
} // detail

/** Check if a buffer sequence contains no data.
/** Return the total byte count across all buffers in a sequence.

@return `true` if all buffers have size zero or the sequence
is empty.
Sums the `size()` of each buffer in the sequence. This differs
from `buffer_length` which counts the number of buffer elements.

@param bs The buffer sequence.

@return The total number of bytes across all buffers in the sequence.

@par Example
@code
std::array<mutable_buffer, 2> bufs = { ... };
std::size_t total = buffer_size( bufs ); // sum of both sizes
@endcode
*/
constexpr struct buffer_empty_mrdocs_workaround_t
constexpr detail::buffer_size_fn buffer_size {};

namespace detail {
struct buffer_empty_fn
{
// See note on buffer_size above — same union-storage false positive.
#if defined(__GNUC__) && !defined(__clang__)
Expand All @@ -321,7 +341,17 @@ constexpr struct buffer_empty_mrdocs_workaround_t
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
} buffer_empty {};
};
} // detail

/** Check if a buffer sequence contains no data.

@param bs The buffer sequence.

@return `true` if all buffers have size zero or the sequence
is empty.
*/
constexpr detail::buffer_empty_fn buffer_empty {};

namespace detail {

Expand Down
44 changes: 24 additions & 20 deletions include/boost/capy/buffers/buffer_copy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,8 @@
namespace boost {
namespace capy {

/** Copy the contents of a buffer sequence into another buffer sequence.

This function copies bytes from the constant buffer sequence `src` into
the mutable buffer sequence `dest`, stopping when any limit is reached.

@par Constraints
@code
MutableBufferSequence<decltype(dest)> &&
ConstBufferSequence<decltype(src)>
@endcode

@return The number of bytes copied, equal to
`std::min(size(dest), size(src), at_most)`.

@param dest The destination buffer sequence.
@param src The source buffer sequence.
@param at_most The maximum bytes to copy. Default copies all available.
*/
constexpr struct buffer_copy_mrdocs_workaround_t
namespace detail {
struct buffer_copy_fn
{
template<
MutableBufferSequence MB,
Expand Down Expand Up @@ -100,7 +83,28 @@ constexpr struct buffer_copy_mrdocs_workaround_t
}
return total;
}
} buffer_copy {};
};
} // detail

/** Copy the contents of a buffer sequence into another buffer sequence.

This function copies bytes from the constant buffer sequence `src` into
the mutable buffer sequence `dest`, stopping when any limit is reached.

@par Constraints
@code
MutableBufferSequence<decltype(dest)> &&
ConstBufferSequence<decltype(src)>
@endcode

@return The number of bytes copied, equal to
`std::min(size(dest), size(src), at_most)`.

@param dest The destination buffer sequence.
@param src The source buffer sequence.
@param at_most The maximum bytes to copy. Default copies all available.
*/
constexpr detail::buffer_copy_fn buffer_copy {};

} // capy
} // boost
Expand Down
20 changes: 16 additions & 4 deletions include/boost/capy/buffers/front.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@
namespace boost {
namespace capy {

/** Return the first buffer in a sequence.
*/
constexpr struct front_mrdocs_workaround_t
namespace detail {
struct front_fn
{
/// Return the first mutable buffer, or an empty buffer.
template<MutableBufferSequence MutableBufferSequence>
Expand All @@ -44,7 +43,20 @@ constexpr struct front_mrdocs_workaround_t
return *it;
return {};
}
} const front{};
};
} // detail

/** Return the first buffer in a sequence.

For a `MutableBufferSequence` the result is a `mutable_buffer`;
otherwise it is a `const_buffer`.

@param bs The buffer sequence.

@return The first buffer in the sequence, or an empty buffer if the
sequence is empty.
*/
constexpr detail::front_fn const front{};

} // capy
} // boost
Expand Down
6 changes: 2 additions & 4 deletions include/boost/capy/io_result.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ struct [[nodiscard]] io_result
{
}

/// @cond
template<std::size_t I>
decltype(auto) get() & noexcept
{
Expand All @@ -82,10 +81,9 @@ struct [[nodiscard]] io_result
if constexpr (I == 0) return std::move(ec);
else return std::get<I - 1>(std::move(values));
}
/// @endcond
};

/// @cond
#if !defined(BOOST_CAPY_MRDOCS)
template<std::size_t I, class... Ts>
decltype(auto) get(io_result<Ts...>& r) noexcept
{
Expand All @@ -103,7 +101,7 @@ decltype(auto) get(io_result<Ts...>&& r) noexcept
{
return std::move(r).template get<I>();
}
/// @endcond
#endif

} // namespace capy
} // namespace boost
Expand Down
Loading