[utils] Mark dawn::Span satisfying ranges::view/borrowed_range This is necessary to allow dawn::Span to be implicitly converted to std::span. Modifies the CompatibleRange condition to check range concepts and fix FakedRang types used in tests to be actual ranges with begin/end. Add begin/end (and tests) to ityp::stack_vec to make it a range and add static_assert in other ityp:: containers to check that there are considered contiguous_range. Bug: 524776858 Change-Id: I8909b4c92b56b72754c83db9f39432d61cadef17 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/319875 Reviewed-by: Loko Kung <lokokung@google.com> Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Kai Ninomiya <kainino@chromium.org>
diff --git a/src/dawn/common/ityp_stack_vec.h b/src/dawn/common/ityp_stack_vec.h index aeb0285..71fb9a7 100644 --- a/src/dawn/common/ityp_stack_vec.h +++ b/src/dawn/common/ityp_stack_vec.h
@@ -51,8 +51,10 @@ Base::resize(checked_cast<size_t>(size), value); } + using Base::begin; using Base::data; using Base::empty; + using Base::end; constexpr Value& operator[](Index i) { #if !defined(ABSL_OPTION_HARDENED) || ABSL_OPTION_HARDENED == 0 || \
diff --git a/src/dawn/tests/unittests/ITypArrayTests.cpp b/src/dawn/tests/unittests/ITypArrayTests.cpp index e686883..a51f6d3 100644 --- a/src/dawn/tests/unittests/ITypArrayTests.cpp +++ b/src/dawn/tests/unittests/ITypArrayTests.cpp
@@ -25,6 +25,8 @@ // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include <ranges> + #include "src/dawn/common/ityp_array.h" #include "src/utils/gtest.h" #include "src/utils/typed_integer.h" @@ -47,6 +49,9 @@ static_assert(kArr.at(Key(7u)) == Val(7u)); static_assert(kArr.size() == Key(10u)); }; + + // Check that ityp::array can be used as a range. + static_assert(std::ranges::contiguous_range<Array>); }; // Test that values can be set at an index and retrieved from the same index.
diff --git a/src/dawn/tests/unittests/ITypStackVecTests.cpp b/src/dawn/tests/unittests/ITypStackVecTests.cpp index c79e359..3dbed0f 100644 --- a/src/dawn/tests/unittests/ITypStackVecTests.cpp +++ b/src/dawn/tests/unittests/ITypStackVecTests.cpp
@@ -25,6 +25,7 @@ // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include <ranges> #include <utility> #include "src/dawn/common/ityp_stack_vec.h" @@ -40,6 +41,9 @@ using Val = TypedInteger<struct ValT, uint32_t>; using StackVec = ityp::stack_vec<Key, Val, 10>; + + // Check that ityp::stack_vec can be used as a range. + static_assert(std::ranges::contiguous_range<StackVec>); }; // Test creation and initialization of the stack_vec. @@ -61,6 +65,23 @@ } } +// Test that the vector can be iterated in order with a range-based for loop +TEST_F(ITypStackVecTest, RangeBasedIteration) { + StackVec vec(Key(10u)); + + // Assign in a non-const range-based for loop + uint32_t i = 0; + for (Val& val : vec) { + val = Val(i); + } + + // Check values in a const range-based for loop + i = 0; + for (Val val : static_cast<const StackVec&>(vec)) { + ASSERT_EQ(val, vec[Key(i++)]); + } +} + // Name "*DeathTest" per https://google.github.io/googletest/advanced.html#death-test-naming using ITypStackVecDeathTest = ITypStackVecTest;
diff --git a/src/dawn/tests/unittests/ITypVectorTests.cpp b/src/dawn/tests/unittests/ITypVectorTests.cpp index d84b9be..b413172 100644 --- a/src/dawn/tests/unittests/ITypVectorTests.cpp +++ b/src/dawn/tests/unittests/ITypVectorTests.cpp
@@ -26,6 +26,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <array> +#include <ranges> #include <utility> #include "src/dawn/common/ityp_vector.h" @@ -41,6 +42,9 @@ using Val = TypedInteger<struct ValT, uint32_t>; using Vector = ityp::vector<Key, Val>; + + // Check that ityp::vector can be used as a range. + static_assert(std::ranges::contiguous_range<Vector>); }; // Name "*DeathTest" per https://google.github.io/googletest/advanced.html#death-test-naming
diff --git a/src/utils/span.h b/src/utils/span.h index e10e0d7..682d77f 100644 --- a/src/utils/span.h +++ b/src/utils/span.h
@@ -31,6 +31,7 @@ #include <concepts> #include <limits> #include <memory> +#include <ranges> #include <span> #include "src/utils/numeric.h" @@ -58,7 +59,7 @@ namespace detail { template <typename T, HasUnsignedUnderlyingType Index, typename PtrType> class SpanBase; -} +} // namespace detail // A direct replacement for std::span<T> template <typename T> @@ -73,7 +74,16 @@ // The equivalent of std::dynamic_extent for the given index type. template <typename Index> inline constexpr Index DynamicExtent = std::numeric_limits<Index>::max(); +} // namespace dawn +// Mark `SpanBase` as satisfying the `view` and `borrowed_range` concepts. +template <typename T, typename Index, typename PtrType> +inline constexpr bool std::ranges::enable_view<dawn::detail::SpanBase<T, Index, PtrType>> = true; +template <typename T, typename Index, typename PtrType> +inline constexpr bool + std::ranges::enable_borrowed_range<dawn::detail::SpanBase<T, Index, PtrType>> = true; + +namespace dawn { namespace detail { template <typename From, typename To> @@ -84,10 +94,13 @@ LegalDataConversion<std::remove_reference_t<std::iter_reference_t<It>>, T>; template <typename T, typename Index, typename R> -concept CompatibleRange = requires(R r) { - { r.data() } -> std::convertible_to<T*>; - { r.size() } -> std::same_as<Index>; -}; +concept CompatibleRange = + std::ranges::contiguous_range<R> && // + (std::ranges::borrowed_range<R> || std::is_const_v<T>) && + LegalDataConversion<std::remove_reference_t<std::ranges::range_reference_t<R>>, T> && + requires(R r) { + { r.size() } -> std::same_as<Index>; + }; // DIFF: only dynamic_extent is supported at the moment because Dawn might not need spans with // static extents. @@ -147,7 +160,7 @@ } } - // Constructor from a "range-like" that provides `T* data()` and `Index size()`. Note that this + // Constructor from a range that provides `T* data()` and `Index size()`. Note that this // is quite different from Chromium's base::span constructor from ranges because adapting that // constructor to support TypedInteger for Index would be extremely challenging. Will // DAWN_CHECK() if the size doesn't fit in a size_t.
diff --git a/src/utils/span_nocompile.nc b/src/utils/span_nocompile.nc index 7e254e3..34f3160 100644 --- a/src/utils/span_nocompile.nc +++ b/src/utils/span_nocompile.nc
@@ -42,6 +42,8 @@ struct FakeRange { size_t size() const { return kSpanData.size(); } const int* data() const { return kSpanData.data(); } + auto begin() { return kSpanData.begin(); } + auto end() { return kSpanData.end(); } }; struct FakeTypedRange { @@ -49,6 +51,8 @@ return Index{uint32_t{kSpanData.size()}}; } const int* data() const { return kSpanData.data(); } + auto begin() { return kSpanData.begin(); } + auto end() { return kSpanData.end(); } }; void TestConstPointerToNonConstSpan() {
diff --git a/src/utils/span_tests.cc b/src/utils/span_tests.cc index 2e83894..3e234fc 100644 --- a/src/utils/span_tests.cc +++ b/src/utils/span_tests.cc
@@ -44,6 +44,8 @@ struct FakeRange { size_t size() const { return kSpanData.size(); } const int* data() const { return kSpanData.data(); } + auto begin() { return kSpanData.begin(); } + auto end() { return kSpanData.end(); } }; struct FakeTypedRange { @@ -51,6 +53,8 @@ return Index{uint32_t{kSpanData.size()}}; } const int* data() const { return kSpanData.data(); } + auto begin() { return kSpanData.begin(); } + auto end() { return kSpanData.end(); } }; struct FakeTyped64Range { @@ -58,6 +62,8 @@ return Index64{uint64_t{kSpanData.size()}}; } const int* data() const { return kSpanData.data(); } + auto begin() { return kSpanData.begin(); } + auto end() { return kSpanData.end(); } }; TEST(SpanTest, Constructor_Default) {