Skip to content

Commit

Permalink
dev: span utility improvements (#4398)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
lgritz committed Aug 31, 2024
1 parent f460da5 commit a534a39
Showing 1 changed file with 43 additions and 15 deletions.
58 changes: 43 additions & 15 deletions src/include/OpenImageIO/span_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<typename T, span_size_t Extent>
span<const std::byte,
((Extent == dynamic_extent) ? dynamic_extent : sizeof(T) * Extent)>
as_bytes(span<T, Extent> s) noexcept
{
return { reinterpret_cast<const std::byte*>(s.data()), s.size_bytes() };
}



/// Convert a span of any type to a span of mutable bytes covering the same
/// range of memory.
template<class T, span_size_t Extent, OIIO_ENABLE_IF(!std::is_const<T>::value)>
span<std::byte,
((Extent == dynamic_extent) ? dynamic_extent : sizeof(T) * Extent)>
as_writable_bytes(span<T, Extent> s) noexcept
{
return { reinterpret_cast<std::byte*>(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<typename T>
size_t
spancpy(span<T> dst, size_t dstoffset, cspan<T> src, size_t srcoffset, size_t n)
spancpy(span<T> dst, size_t dstoffset, cspan<T> 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;
}
Expand All @@ -130,16 +155,17 @@ spancpy(span<T> dst, size_t dstoffset, cspan<T> 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<typename T>
size_t
spanset(span<T> dst, size_t offset, const T& val, size_t n)
spanset(span<T> 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;
Expand All @@ -153,16 +179,18 @@ spanset(span<T> 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<typename T>
size_t
spanzero(span<T> dst, size_t offset, size_t n)
spanzero(span<T> 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;
}
Expand Down

0 comments on commit a534a39

Please sign in to comment.