Skip to content

Commit 25eb718

Browse files
authored
api: image_span_within_span (#4784)
A utility to confirm that an image_span (possibly with non-contiguous strides) entirely fits within another contiguous span. Signed-off-by: Larry Gritz <lg@larrygritz.com>
1 parent 8031b57 commit 25eb718

3 files changed

Lines changed: 136 additions & 0 deletions

File tree

src/include/OpenImageIO/image_span.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,5 +387,21 @@ as_image_span_writable_bytes(const image_span<T, Rank>& src) noexcept
387387
}
388388

389389

390+
/// Verify that the image_span has all its contents lying within the
391+
/// contiguous span.
392+
OIIO_API bool
393+
image_span_within_span(const image_span<const std::byte>& ispan,
394+
span<const std::byte> contiguous) noexcept;
395+
396+
/// image_span_within_span() for generic span types. Just reduce to
397+
/// const byte versions.
398+
template<typename T, size_t Trank, typename S>
399+
bool
400+
image_span_within_span(const image_span<T, Trank>& ispan,
401+
span<S> contiguous) noexcept
402+
{
403+
return image_span_within_span(as_image_span_bytes(ispan),
404+
as_bytes(contiguous));
405+
}
390406

391407
OIIO_NAMESPACE_END

src/libOpenImageIO/image_span_test.cpp

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,83 @@ benchmark_image_span_passing()
467467

468468

469469

470+
void
471+
test_image_span_within_span()
472+
{
473+
print("\ntest_image_span_within_span\n");
474+
475+
const int nchans = 3, xres = 5, yres = 7, zres = 11;
476+
const int chstride = sizeof(float), xstride = chstride * nchans,
477+
ystride = xstride * xres, zstride = ystride * yres;
478+
float array[nchans * xres * yres * zres];
479+
cspan<float> aspan(array);
480+
// It better worrk with the same origin and default strides
481+
OIIO_CHECK_ASSERT(
482+
image_span_within_span(image_span(array, nchans, xres, yres, zres,
483+
chstride, xstride, ystride, zstride),
484+
aspan));
485+
// Make sure too big are recognized
486+
OIIO_CHECK_FALSE(
487+
image_span_within_span(image_span(array, nchans, xres, yres, zres,
488+
chstride + 1, xstride, ystride,
489+
zstride),
490+
aspan));
491+
OIIO_CHECK_FALSE(
492+
image_span_within_span(image_span(array, nchans, xres, yres, zres,
493+
chstride, xstride + 1, ystride,
494+
zstride),
495+
aspan));
496+
OIIO_CHECK_FALSE(
497+
image_span_within_span(image_span(array, nchans, xres, yres, zres,
498+
chstride, xstride, ystride + 1,
499+
zstride),
500+
aspan));
501+
OIIO_CHECK_FALSE(
502+
image_span_within_span(image_span(array, nchans, xres, yres, zres,
503+
chstride, xstride, ystride,
504+
zstride + 1),
505+
aspan));
506+
// Make sure negagive strides used CORRECTLY are recognized
507+
OIIO_CHECK_FALSE(
508+
image_span_within_span(image_span(array, nchans, xres, yres, zres,
509+
-chstride, xstride, ystride, zstride),
510+
aspan));
511+
OIIO_CHECK_FALSE(
512+
image_span_within_span(image_span(array, nchans, xres, yres, zres,
513+
chstride, -xstride, ystride, zstride),
514+
aspan));
515+
OIIO_CHECK_FALSE(
516+
image_span_within_span(image_span(array, nchans, xres, yres, zres,
517+
chstride, xstride, -ystride, zstride),
518+
aspan));
519+
OIIO_CHECK_FALSE(
520+
image_span_within_span(image_span(array, nchans, xres, yres, zres,
521+
chstride, xstride, ystride, -zstride),
522+
aspan));
523+
// Make sure negagive strides used CORRECTLY are recognized
524+
OIIO_CHECK_ASSERT(
525+
image_span_within_span(image_span(array + nchans - 1, nchans, xres,
526+
yres, zres, -chstride, xstride,
527+
ystride, zstride),
528+
aspan));
529+
OIIO_CHECK_ASSERT(
530+
image_span_within_span(image_span(array + (xres - 1) * nchans, nchans,
531+
xres, yres, zres, chstride, -xstride,
532+
ystride, zstride),
533+
aspan));
534+
OIIO_CHECK_ASSERT(
535+
image_span_within_span(image_span(array + (yres - 1) * xres * nchans,
536+
nchans, xres, yres, zres, chstride,
537+
xstride, -ystride, zstride),
538+
aspan));
539+
OIIO_CHECK_ASSERT(image_span_within_span(
540+
image_span(array + (zres - 1) * xres * yres * nchans, nchans, xres,
541+
yres, zres, chstride, xstride, ystride, -zstride),
542+
aspan));
543+
}
544+
545+
546+
470547
int
471548
main(int /*argc*/, char* /*argv*/[])
472549
{
@@ -496,6 +573,8 @@ main(int /*argc*/, char* /*argv*/[])
496573
test_image_span_convert_image<uint16_t, half>();
497574
test_image_span_convert_image<half, uint16_t>();
498575

576+
test_image_span_within_span();
577+
499578
benchmark_image_span_passing();
500579

501580
return unit_test_failures;

src/libOpenImageIO/imageio.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,4 +1356,45 @@ wrap_mirror(int& coord, int origin, int width)
13561356
}
13571357

13581358

1359+
1360+
/// Verify that the image_span has all its contents lying within the
1361+
/// contiguous span.
1362+
bool
1363+
image_span_within_span(const image_span<const std::byte>& ispan,
1364+
span<const std::byte> contiguous) noexcept
1365+
{
1366+
// Start with first,last being the first byte of pixel 0, channel 0
1367+
const std::byte* first = ispan.data(); // first byte of ispan
1368+
const std::byte* last = ispan.data(); // last byte of ispan
1369+
// Extend them to the start of the first pixel of the first and last image
1370+
// plane.
1371+
if (ispan.zstride() > 0)
1372+
last += ispan.zstride() * (ispan.depth() - 1);
1373+
else
1374+
first += ispan.zstride() * (ispan.depth() - 1); // neg stride
1375+
// Extend them to the start of the first pixel of the first and last
1376+
// scanline of the first and last image plane.
1377+
if (ispan.ystride() > 0)
1378+
last += ispan.ystride() * (ispan.height() - 1);
1379+
else
1380+
first += ispan.ystride() * (ispan.height() - 1); // neg stride
1381+
// Extend them to the start of the first pixel of the first and last
1382+
// column of the first and last scanline of the first and last image
1383+
// plane.
1384+
if (ispan.xstride() > 0)
1385+
last += ispan.xstride() * (ispan.width() - 1);
1386+
else
1387+
first += ispan.xstride() * (ispan.width() - 1); // neg stride
1388+
// Make sure they cover the whole of those extreme pixels
1389+
if (ispan.chanstride() > 0)
1390+
last += ispan.chanstride() * (ispan.nchannels() - 1);
1391+
else
1392+
first += ispan.chanstride() * (ispan.nchannels() - 1); // neg stride
1393+
// Make sure last covers the whole data type
1394+
last += ispan.chansize() - 1;
1395+
return (first >= contiguous.data()
1396+
&& last < contiguous.data() + contiguous.size());
1397+
}
1398+
1399+
13591400
OIIO_NAMESPACE_END

0 commit comments

Comments
 (0)