From 26a71c73e1c0da52a1230fbafe6ec2a5c34e30f7 Mon Sep 17 00:00:00 2001 From: Larry Gritz Date: Tue, 27 Aug 2024 23:43:02 -0700 Subject: [PATCH] dev: span utility improvements * Added as_bytes and as_writable_bytes that convert spans of arbitrary type to spans of std::byte. (This mimics C++20 utilities of the same name.) * spancopy, spanset, spanzero: add parameter defaults for the common case of wanting to do the operation on the whole span, also simplify the bound-limiting logic in those functions a bit (but still performing precisely the same task). Signed-off-by: Larry Gritz --- src/include/OpenImageIO/span_util.h | 58 +++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/src/include/OpenImageIO/span_util.h b/src/include/OpenImageIO/span_util.h index aa1c839f5e..24354ee156 100644 --- a/src/include/OpenImageIO/span_util.h +++ b/src/include/OpenImageIO/span_util.h @@ -99,25 +99,50 @@ make_cspan(const T* data, span_size_t size) // cspan from ptr + size +/// Convert a span of any type to a span of bytes covering the same range of +/// memory. +template +span +as_bytes(span s) noexcept +{ + return { reinterpret_cast(s.data()), s.size_bytes() }; +} + + + +/// Convert a span of any type to a span of mutable bytes covering the same +/// range of memory. +template::value)> +span +as_writable_bytes(span s) noexcept +{ + return { reinterpret_cast(s.data()), s.size_bytes() }; +} + + + /// Try to copy `n` items of type `T` from `src[srcoffset...]` to /// `dst[dstoffset...]`. Don't read or write outside the respective span /// boundaries. Return the number of items actually copied, which should be /// `n` if the operation was fully successful, but may be less if the request /// could not be satisfied while staying within the span bounds. /// +/// If `n` is not supplied, it will default to filling as much of `src` (from +/// `srcoffset` to its end) as will fit into `dst`. If `srcoffset` is not +/// supplied, it will default to 0 (the beginning of `src`). +/// /// This is intended to be used as a memory-safe replacement for memcpy if /// you're using spans. template size_t -spancpy(span dst, size_t dstoffset, cspan src, size_t srcoffset, size_t n) +spancpy(span dst, size_t dstoffset, cspan src, size_t srcoffset = 0, + size_t n = size_t(-1)) { // Where do the requests end (limited by span boundaries)? - size_t dstend = std::min(dstoffset + n, std::size(dst)); - size_t srcend = std::min(srcoffset + n, std::size(src)); - // How many can/should we copy? - size_t ndst = dstend - dstoffset; - size_t nsrc = srcend - srcoffset; - n = std::min(ndst, nsrc); + n = std::min(n, src.size() - srcoffset); + n = std::min(n, dst.size() - dstoffset); memcpy(dst.data() + dstoffset, src.data() + srcoffset, n * sizeof(T)); return n; } @@ -130,16 +155,17 @@ spancpy(span dst, size_t dstoffset, cspan src, size_t srcoffset, size_t n) /// if the request could not be satisfied while staying within the span /// bounds. /// +/// If `n` is not supplied, it will default to filling from `offset` to the +/// end of the span. +/// /// This is intended to be used as a memory-safe replacement for memset if /// you're using spans. template size_t -spanset(span dst, size_t offset, const T& val, size_t n) +spanset(span dst, size_t offset, const T& val, size_t n = size_t(-1)) { // Where does the request end (limited by span boundary)? - size_t dstend = std::min(offset + n, std::size(dst)); - // How many can/should we copy? - n = dstend - offset; + n = std::min(n, dst.size() - offset); for (size_t i = 0; i < n; ++i) dst[offset + i] = val; return n; @@ -153,16 +179,18 @@ spanset(span dst, size_t offset, const T& val, size_t n) /// may be less if the request could not be satisfied while staying within the /// span bounds. /// +/// If `n` is not supplied, it will default to filling from `offset` to the +/// end of the span. If `offset` is not supplied, it will default 0 (the +/// beginning of the span). +/// /// This is intended to be used as a memory-safe replacement for /// `memset(ptr,0,n)` if you're using spans. template size_t -spanzero(span dst, size_t offset, size_t n) +spanzero(span dst, size_t offset = 0, size_t n = size_t(-1)) { // Where does the request end (limited by span boundary)? - size_t dstend = std::min(offset + n, std::size(dst)); - // How many can/should we copy? - n = dstend - offset; + n = std::min(n, dst.size() - offset); memset(dst.data() + offset, 0, n * sizeof(T)); return n; }