Add a Python-like Range iterator.

This is to help iterate over ranges of typed integers.

Bug: dawn:2222
Change-Id: I63c827cf98e8cf07a8bc2be3bc2d01c6799e97af
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/162503
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Loko Kung <lokokung@google.com>
diff --git a/src/dawn/common/BUILD.gn b/src/dawn/common/BUILD.gn
index f175c4e..6d9d917 100644
--- a/src/dawn/common/BUILD.gn
+++ b/src/dawn/common/BUILD.gn
@@ -274,6 +274,7 @@
       "PlacementAllocated.h",
       "Platform.h",
       "Preprocessor.h",
+      "Range.h",
       "Ref.h",
       "RefBase.h",
       "RefCounted.cpp",
diff --git a/src/dawn/common/CMakeLists.txt b/src/dawn/common/CMakeLists.txt
index 4d4a878..f676382 100644
--- a/src/dawn/common/CMakeLists.txt
+++ b/src/dawn/common/CMakeLists.txt
@@ -77,6 +77,7 @@
     "PlacementAllocated.h"
     "Platform.h"
     "Preprocessor.h"
+    "Range.h"
     "Ref.h"
     "RefBase.h"
     "RefCounted.cpp"
diff --git a/src/dawn/common/Range.h b/src/dawn/common/Range.h
new file mode 100644
index 0000000..8ab2cf4
--- /dev/null
+++ b/src/dawn/common/Range.h
@@ -0,0 +1,85 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// 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.
+
+#ifndef SRC_DAWN_COMMON_RANGE_H_
+#define SRC_DAWN_COMMON_RANGE_H_
+
+#include <type_traits>
+#include <utility>
+
+namespace dawn {
+
+// An iterator over a range of numbers. Simplified version of Python's range() iterator that works
+// with any integer type (including ityp).
+//
+// Iterates over [0, end) in order:
+//
+//   for (auto i : Range(end)) { ... }
+//
+// Iterates over [start, end) in order:
+//
+//   for (auto i = Range(start, end)) { ... }
+template <typename Integer>
+class BeginEndRange {
+  public:
+    BeginEndRange(Integer begin, Integer end) : mBegin(begin), mEnd(end) {}
+
+    class Iterator final {
+      public:
+        explicit Iterator(Integer value) : mValue(value) {}
+        bool operator==(const Iterator& other) const { return other.mValue == mValue; }
+        bool operator!=(const Iterator& other) const { return !(*this == other); }
+        Iterator& operator++() {
+            mValue++;
+            return *this;
+        }
+        Integer operator*() const { return mValue; }
+
+      private:
+        Integer mValue;
+    };
+
+    Iterator begin() const { return Iterator(mBegin); }
+    Iterator end() const { return Iterator(mEnd); }
+
+  private:
+    Integer mBegin;
+    Integer mEnd;
+};
+
+template <typename Integer>
+BeginEndRange<Integer> Range(Integer end) {
+    return {Integer{}, end};
+}
+template <typename Integer>
+BeginEndRange<Integer> Range(Integer begin, Integer end) {
+    return {begin, end};
+}
+
+}  // namespace dawn
+
+#endif  // SRC_DAWN_COMMON_RANGE_H_
diff --git a/src/dawn/tests/BUILD.gn b/src/dawn/tests/BUILD.gn
index de77a43..15b5c6d 100644
--- a/src/dawn/tests/BUILD.gn
+++ b/src/dawn/tests/BUILD.gn
@@ -325,6 +325,7 @@
     "unittests/PerStageTests.cpp",
     "unittests/PerThreadProcTests.cpp",
     "unittests/PlacementAllocatedTests.cpp",
+    "unittests/RangeTests.cpp",
     "unittests/RefBaseTests.cpp",
     "unittests/RefCountedTests.cpp",
     "unittests/ResultTests.cpp",
diff --git a/src/dawn/tests/unittests/RangeTests.cpp b/src/dawn/tests/unittests/RangeTests.cpp
new file mode 100644
index 0000000..0f0dd9d
--- /dev/null
+++ b/src/dawn/tests/unittests/RangeTests.cpp
@@ -0,0 +1,89 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// 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 "dawn/common/Compiler.h"
+#include "dawn/common/Range.h"
+#include "dawn/common/TypedInteger.h"
+#include "gtest/gtest.h"
+
+namespace dawn {
+namespace {
+
+// Test that iterating an empty range doesn't iterate at all.
+TEST(RangeTests, Empty) {
+    for (auto i : Range(0)) {
+        // Silence a -Wunreachable-code-loop-increment
+        if ((0)) {
+            continue;
+        }
+        DAWN_UNUSED(i);
+        FAIL();
+    }
+    for (auto i : Range(0, 0)) {
+        // Silence a -Wunreachable-code-loop-increment
+        if ((0)) {
+            continue;
+        }
+        DAWN_UNUSED(i);
+        FAIL();
+    }
+}
+
+// Test iterating with just an end.
+TEST(RangeTests, JustEnd) {
+    int count = 0;
+    for (auto i : Range(45)) {
+        ASSERT_EQ(count, i);
+        count++;
+    }
+    ASSERT_EQ(count, 45);
+}
+
+// Test iterating with a start and an end.
+TEST(RangeTests, StartAndEnd) {
+    int count = 18;
+    for (auto i : Range(18, 45)) {
+        ASSERT_EQ(count, i);
+        count++;
+    }
+    ASSERT_EQ(count, 45);
+}
+
+// Test iterating with a start and an end.
+TEST(RangeTests, StartAndEnd_ITyp) {
+    using Int = TypedInteger<struct IntT, int>;
+
+    Int count{18};
+    for (auto i : Range(Int{18}, Int{45})) {
+        ASSERT_EQ(count, i);
+        count++;
+    }
+    ASSERT_EQ(count, Int{45});
+}
+
+}  // anonymous namespace
+}  // namespace dawn