Skip to content

Commit a534a39

Browse files
authored
dev: span utility improvements (#4398)
* 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 <lg@larrygritz.com>
1 parent f460da5 commit a534a39

File tree

1 file changed

+43
-15
lines changed

1 file changed

+43
-15
lines changed

src/include/OpenImageIO/span_util.h

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -99,25 +99,50 @@ make_cspan(const T* data, span_size_t size) // cspan from ptr + size
9999

100100

101101

102+
/// Convert a span of any type to a span of bytes covering the same range of
103+
/// memory.
104+
template<typename T, span_size_t Extent>
105+
span<const std::byte,
106+
((Extent == dynamic_extent) ? dynamic_extent : sizeof(T) * Extent)>
107+
as_bytes(span<T, Extent> s) noexcept
108+
{
109+
return { reinterpret_cast<const std::byte*>(s.data()), s.size_bytes() };
110+
}
111+
112+
113+
114+
/// Convert a span of any type to a span of mutable bytes covering the same
115+
/// range of memory.
116+
template<class T, span_size_t Extent, OIIO_ENABLE_IF(!std::is_const<T>::value)>
117+
span<std::byte,
118+
((Extent == dynamic_extent) ? dynamic_extent : sizeof(T) * Extent)>
119+
as_writable_bytes(span<T, Extent> s) noexcept
120+
{
121+
return { reinterpret_cast<std::byte*>(s.data()), s.size_bytes() };
122+
}
123+
124+
125+
102126
/// Try to copy `n` items of type `T` from `src[srcoffset...]` to
103127
/// `dst[dstoffset...]`. Don't read or write outside the respective span
104128
/// boundaries. Return the number of items actually copied, which should be
105129
/// `n` if the operation was fully successful, but may be less if the request
106130
/// could not be satisfied while staying within the span bounds.
107131
///
132+
/// If `n` is not supplied, it will default to filling as much of `src` (from
133+
/// `srcoffset` to its end) as will fit into `dst`. If `srcoffset` is not
134+
/// supplied, it will default to 0 (the beginning of `src`).
135+
///
108136
/// This is intended to be used as a memory-safe replacement for memcpy if
109137
/// you're using spans.
110138
template<typename T>
111139
size_t
112-
spancpy(span<T> dst, size_t dstoffset, cspan<T> src, size_t srcoffset, size_t n)
140+
spancpy(span<T> dst, size_t dstoffset, cspan<T> src, size_t srcoffset = 0,
141+
size_t n = size_t(-1))
113142
{
114143
// Where do the requests end (limited by span boundaries)?
115-
size_t dstend = std::min(dstoffset + n, std::size(dst));
116-
size_t srcend = std::min(srcoffset + n, std::size(src));
117-
// How many can/should we copy?
118-
size_t ndst = dstend - dstoffset;
119-
size_t nsrc = srcend - srcoffset;
120-
n = std::min(ndst, nsrc);
144+
n = std::min(n, src.size() - srcoffset);
145+
n = std::min(n, dst.size() - dstoffset);
121146
memcpy(dst.data() + dstoffset, src.data() + srcoffset, n * sizeof(T));
122147
return n;
123148
}
@@ -130,16 +155,17 @@ spancpy(span<T> dst, size_t dstoffset, cspan<T> src, size_t srcoffset, size_t n)
130155
/// if the request could not be satisfied while staying within the span
131156
/// bounds.
132157
///
158+
/// If `n` is not supplied, it will default to filling from `offset` to the
159+
/// end of the span.
160+
///
133161
/// This is intended to be used as a memory-safe replacement for memset if
134162
/// you're using spans.
135163
template<typename T>
136164
size_t
137-
spanset(span<T> dst, size_t offset, const T& val, size_t n)
165+
spanset(span<T> dst, size_t offset, const T& val, size_t n = size_t(-1))
138166
{
139167
// Where does the request end (limited by span boundary)?
140-
size_t dstend = std::min(offset + n, std::size(dst));
141-
// How many can/should we copy?
142-
n = dstend - offset;
168+
n = std::min(n, dst.size() - offset);
143169
for (size_t i = 0; i < n; ++i)
144170
dst[offset + i] = val;
145171
return n;
@@ -153,16 +179,18 @@ spanset(span<T> dst, size_t offset, const T& val, size_t n)
153179
/// may be less if the request could not be satisfied while staying within the
154180
/// span bounds.
155181
///
182+
/// If `n` is not supplied, it will default to filling from `offset` to the
183+
/// end of the span. If `offset` is not supplied, it will default 0 (the
184+
/// beginning of the span).
185+
///
156186
/// This is intended to be used as a memory-safe replacement for
157187
/// `memset(ptr,0,n)` if you're using spans.
158188
template<typename T>
159189
size_t
160-
spanzero(span<T> dst, size_t offset, size_t n)
190+
spanzero(span<T> dst, size_t offset = 0, size_t n = size_t(-1))
161191
{
162192
// Where does the request end (limited by span boundary)?
163-
size_t dstend = std::min(offset + n, std::size(dst));
164-
// How many can/should we copy?
165-
n = dstend - offset;
193+
n = std::min(n, dst.size() - offset);
166194
memset(dst.data() + offset, 0, n * sizeof(T));
167195
return n;
168196
}

0 commit comments

Comments
 (0)