/* SPDX-License-Identifier: Apache-2.0 */ #include "BLI_span.hh" #include "BLI_strict_flags.h" #include "BLI_vector.hh" #include "testing/testing.h" namespace blender::tests { TEST(span, FromSmallVector) { Vector a = {1, 2, 3}; Span a_span = a; EXPECT_EQ(a_span.size(), 3); EXPECT_EQ(a_span[0], 1); EXPECT_EQ(a_span[1], 2); EXPECT_EQ(a_span[2], 3); } TEST(span, AddConstToPointer) { int a = 0; std::vector vec = {&a}; Span span = vec; Span const_span = span; EXPECT_EQ(const_span.size(), 1); } TEST(span, IsReferencing) { int array[] = {3, 5, 8}; MutableSpan span(array, ARRAY_SIZE(array)); EXPECT_EQ(span.size(), 3); EXPECT_EQ(span[1], 5); array[1] = 10; EXPECT_EQ(span[1], 10); } TEST(span, DropBack) { Vector a = {4, 5, 6, 7}; auto slice = Span(a).drop_back(2); EXPECT_EQ(slice.size(), 2); EXPECT_EQ(slice[0], 4); EXPECT_EQ(slice[1], 5); } TEST(span, DropBackAll) { Vector a = {4, 5, 6, 7}; auto slice = Span(a).drop_back(a.size()); EXPECT_EQ(slice.size(), 0); } TEST(span, DropFront) { Vector a = {4, 5, 6, 7}; auto slice = Span(a).drop_front(1); EXPECT_EQ(slice.size(), 3); EXPECT_EQ(slice[0], 5); EXPECT_EQ(slice[1], 6); EXPECT_EQ(slice[2], 7); } TEST(span, DropFrontLargeN) { Vector a = {1, 2, 3, 4, 5}; Span slice1 = Span(a).drop_front(100); MutableSpan slice2 = MutableSpan(a).drop_front(100); EXPECT_TRUE(slice1.is_empty()); EXPECT_TRUE(slice2.is_empty()); } TEST(span, DropFrontAll) { Vector a = {4, 5, 6, 7}; auto slice = Span(a).drop_front(a.size()); EXPECT_EQ(slice.size(), 0); } TEST(span, TakeFront) { Vector a = {4, 5, 6, 7}; auto slice = Span(a).take_front(2); EXPECT_EQ(slice.size(), 2); EXPECT_EQ(slice[0], 4); EXPECT_EQ(slice[1], 5); } TEST(span, TakeFrontLargeN) { Vector a = {4, 5, 6, 7}; Span slice1 = Span(a).take_front(100); MutableSpan slice2 = MutableSpan(a).take_front(100); EXPECT_EQ(slice1.size(), 4); EXPECT_EQ(slice2.size(), 4); } TEST(span, TakeBack) { Vector a = {5, 6, 7, 8}; auto slice = Span(a).take_back(2); EXPECT_EQ(slice.size(), 2); EXPECT_EQ(slice[0], 7); EXPECT_EQ(slice[1], 8); } TEST(span, TakeBackLargeN) { Vector a = {3, 4, 5, 6}; Span slice1 = Span(a).take_back(100); MutableSpan slice2 = MutableSpan(a).take_back(100); EXPECT_EQ(slice1.size(), 4); EXPECT_EQ(slice2.size(), 4); } TEST(span, Slice) { Vector a = {4, 5, 6, 7}; auto slice = Span(a).slice(1, 2); EXPECT_EQ(slice.size(), 2); EXPECT_EQ(slice[0], 5); EXPECT_EQ(slice[1], 6); } TEST(span, SliceEmpty) { Vector a = {4, 5, 6, 7}; auto slice = Span(a).slice(2, 0); EXPECT_EQ(slice.size(), 0); } TEST(span, SliceRange) { Vector a = {1, 2, 3, 4, 5}; auto slice = Span(a).slice(IndexRange(2, 2)); EXPECT_EQ(slice.size(), 2); EXPECT_EQ(slice[0], 3); EXPECT_EQ(slice[1], 4); } TEST(span, SliceLargeN) { Vector a = {1, 2, 3, 4, 5}; Span slice1 = Span(a).slice(3, 100); MutableSpan slice2 = MutableSpan(a).slice(3, 100); EXPECT_EQ(slice1.size(), 2); EXPECT_EQ(slice2.size(), 2); EXPECT_EQ(slice1[0], 4); EXPECT_EQ(slice2[0], 4); EXPECT_EQ(slice1[1], 5); EXPECT_EQ(slice2[1], 5); } TEST(span, Contains) { Vector a = {4, 5, 6, 7}; Span a_span = a; EXPECT_TRUE(a_span.contains(4)); EXPECT_TRUE(a_span.contains(5)); EXPECT_TRUE(a_span.contains(6)); EXPECT_TRUE(a_span.contains(7)); EXPECT_FALSE(a_span.contains(3)); EXPECT_FALSE(a_span.contains(8)); } TEST(span, Count) { Vector a = {2, 3, 4, 3, 3, 2, 2, 2, 2}; Span a_span = a; EXPECT_EQ(a_span.count(1), 0); EXPECT_EQ(a_span.count(2), 5); EXPECT_EQ(a_span.count(3), 3); EXPECT_EQ(a_span.count(4), 1); EXPECT_EQ(a_span.count(5), 0); } static void test_ref_from_initializer_list(Span span) { EXPECT_EQ(span.size(), 4); EXPECT_EQ(span[0], 3); EXPECT_EQ(span[1], 6); EXPECT_EQ(span[2], 8); EXPECT_EQ(span[3], 9); } TEST(span, FromInitializerList) { test_ref_from_initializer_list({3, 6, 8, 9}); } TEST(span, FromVector) { std::vector a = {1, 2, 3, 4}; Span a_span(a); EXPECT_EQ(a_span.size(), 4); EXPECT_EQ(a_span[0], 1); EXPECT_EQ(a_span[1], 2); EXPECT_EQ(a_span[2], 3); EXPECT_EQ(a_span[3], 4); } TEST(span, FromArray) { std::array a = {5, 6}; Span a_span(a); EXPECT_EQ(a_span.size(), 2); EXPECT_EQ(a_span[0], 5); EXPECT_EQ(a_span[1], 6); } TEST(span, Fill) { std::array a = {4, 5, 6, 7, 8}; MutableSpan a_span(a); a_span.fill(1); EXPECT_EQ(a[0], 1); EXPECT_EQ(a[1], 1); EXPECT_EQ(a[2], 1); EXPECT_EQ(a[3], 1); EXPECT_EQ(a[4], 1); } TEST(span, FillIndices) { std::array a = {0, 0, 0, 0, 0}; MutableSpan a_span(a); a_span.fill_indices({0, 2, 3}, 1); EXPECT_EQ(a[0], 1); EXPECT_EQ(a[1], 0); EXPECT_EQ(a[2], 1); EXPECT_EQ(a[3], 1); EXPECT_EQ(a[4], 0); } TEST(span, SizeInBytes) { std::array a{}; Span a_span(a); EXPECT_EQ(a_span.size_in_bytes(), int64_t(sizeof(a))); EXPECT_EQ(a_span.size_in_bytes(), 40); } TEST(span, FirstLast) { std::array a = {6, 7, 8, 9}; Span a_span(a); EXPECT_EQ(a_span.first(), 6); EXPECT_EQ(a_span.last(), 9); EXPECT_EQ(a_span.last(1), 8); EXPECT_EQ(a_span.last(2), 7); } TEST(span, FirstLast_OneElement) { int a = 3; Span a_span(&a, 1); EXPECT_EQ(a_span.first(), 3); EXPECT_EQ(a_span.last(), 3); EXPECT_EQ(a_span.last(0), 3); } TEST(span, Get) { std::array a = {5, 6, 7}; Span a_span(a); EXPECT_EQ(a_span.get(0, 42), 5); EXPECT_EQ(a_span.get(1, 42), 6); EXPECT_EQ(a_span.get(2, 42), 7); EXPECT_EQ(a_span.get(3, 42), 42); EXPECT_EQ(a_span.get(4, 42), 42); } TEST(span, ContainsPtr) { std::array a = {5, 6, 7}; int other = 10; Span a_span(a); EXPECT_TRUE(a_span.contains_ptr(&a[0] + 0)); EXPECT_TRUE(a_span.contains_ptr(&a[0] + 1)); EXPECT_TRUE(a_span.contains_ptr(&a[0] + 2)); EXPECT_FALSE(a_span.contains_ptr(&a[0] + 3)); int *ptr_before = reinterpret_cast(uintptr_t(a.data()) - 1); EXPECT_FALSE(a_span.contains_ptr(ptr_before)); EXPECT_FALSE(a_span.contains_ptr(&other)); } TEST(span, FirstIndex) { std::array a = {4, 5, 4, 2, 5}; Span a_span(a); EXPECT_EQ(a_span.first_index(4), 0); EXPECT_EQ(a_span.first_index(5), 1); EXPECT_EQ(a_span.first_index(2), 3); } TEST(span, CastSameSize) { int value = 0; std::array a = {&value, nullptr, nullptr, nullptr}; Span a_span = a; Span new_a_span = a_span.cast(); EXPECT_EQ(a_span.size(), 4); EXPECT_EQ(new_a_span.size(), 4); EXPECT_EQ(a_span[0], &value); EXPECT_EQ(new_a_span[0], (float *)&value); } TEST(span, CastSmallerSize) { std::array a = {3, 4, 5, 6}; Span a_span = a; Span new_a_span = a_span.cast(); EXPECT_EQ(a_span.size(), 4); EXPECT_EQ(new_a_span.size(), 8); } TEST(span, CastLargerSize) { std::array a = {4, 5, 6, 7}; Span a_span = a; Span new_a_span = a_span.cast(); EXPECT_EQ(a_span.size(), 4); EXPECT_EQ(new_a_span.size(), 2); } TEST(span, VoidPointerSpan) { int a; float b; double c; auto func1 = [](Span span) { EXPECT_EQ(span.size(), 3); }; func1({&a, &b, &c}); } TEST(span, CopyFrom) { std::array src = {5, 6, 7, 8}; std::array dst = {1, 2, 3, 4}; EXPECT_EQ(dst[2], 3); MutableSpan(dst).copy_from(src); EXPECT_EQ(dst[0], 5); EXPECT_EQ(dst[1], 6); EXPECT_EQ(dst[2], 7); EXPECT_EQ(dst[3], 8); } TEST(span, ReverseIterator) { std::array src = {4, 5, 6, 7}; Span span = src; Vector reversed_vec; for (auto it = span.rbegin(); it != span.rend(); ++it) { reversed_vec.append(*it); } EXPECT_EQ(reversed_vec.size(), 4); EXPECT_EQ_ARRAY(reversed_vec.data(), Span({7, 6, 5, 4}).data(), 4); } TEST(span, ReverseMutableSpan) { std::array src0 = {}; MutableSpan span0 = src0; span0.reverse(); EXPECT_EQ_ARRAY(span0.data(), Span({}).data(), 0); std::array src1 = {4}; MutableSpan span1 = src1; span1.reverse(); EXPECT_EQ_ARRAY(span1.data(), Span({4}).data(), 1); std::array src2 = {4, 5}; MutableSpan span2 = src2; span2.reverse(); EXPECT_EQ_ARRAY(span2.data(), Span({5, 4}).data(), 2); std::array src5 = {4, 5, 6, 7, 8}; MutableSpan span5 = src5; span5.reverse(); EXPECT_EQ_ARRAY(span5.data(), Span({8, 7, 6, 5, 4}).data(), 5); } TEST(span, MutableReverseIterator) { std::array src = {4, 5, 6, 7}; MutableSpan span = src; Vector reversed_vec; for (auto it = span.rbegin(); it != span.rend(); ++it) { reversed_vec.append(*it); *it += 10; } EXPECT_EQ(reversed_vec.size(), 4); EXPECT_EQ_ARRAY(reversed_vec.data(), Span({7, 6, 5, 4}).data(), 4); EXPECT_EQ_ARRAY(src.data(), Span({14, 15, 16, 17}).data(), 4); } TEST(span, Constexpr) { static constexpr std::array src = {3, 2, 1}; constexpr Span span(src); BLI_STATIC_ASSERT(span[2] == 1, ""); BLI_STATIC_ASSERT(span.size() == 3, ""); BLI_STATIC_ASSERT(span.slice(1, 2).size() == 2, ""); BLI_STATIC_ASSERT(span.has_duplicates__linear_search() == false, ""); std::integral_constant ic; BLI_STATIC_ASSERT(ic.value, ""); EXPECT_EQ(span.slice(1, 2).size(), 2); } TEST(span, ImplicitConversions) { BLI_STATIC_ASSERT((std::is_convertible_v, Span>), ""); BLI_STATIC_ASSERT((std::is_convertible_v, Span>), ""); BLI_STATIC_ASSERT((std::is_convertible_v, Span>), ""); BLI_STATIC_ASSERT((std::is_convertible_v, Span>), ""); BLI_STATIC_ASSERT((std::is_convertible_v, MutableSpan>), ""); BLI_STATIC_ASSERT((!std::is_convertible_v, MutableSpan>), ""); BLI_STATIC_ASSERT((!std::is_convertible_v, Span>), ""); BLI_STATIC_ASSERT((!std::is_convertible_v, MutableSpan>), ""); } TEST(span, Comparison) { std::array a = {3, 4, 5}; std::array b = {3, 4, 5, 6}; EXPECT_FALSE(Span(a) == Span(b)); EXPECT_FALSE(Span(b) == Span(a)); EXPECT_TRUE(Span(a) == Span(b).take_front(3)); EXPECT_TRUE(Span(a) == Span(a)); EXPECT_TRUE(Span(b) == Span(b)); EXPECT_TRUE(Span(a) != Span(b)); EXPECT_TRUE(Span(b) != Span(a)); EXPECT_FALSE(Span(a) != Span(b).take_front(3)); EXPECT_FALSE(Span(a) != Span(a)); } } // namespace blender::tests