[tint][utils] Add Offset and Truncate to Slice

Use them to simplify some IR code.

Change-Id: I43a23484b32003c1c759baf2f0ed33a03c474839
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/136461
Kokoro: Kokoro <noreply+kokoro@google.com>
Auto-Submit: James Price <jrprice@google.com>
Commit-Queue: James Price <jrprice@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/ir/access.h b/src/tint/ir/access.h
index a2bd7eb..c798b13 100644
--- a/src/tint/ir/access.h
+++ b/src/tint/ir/access.h
@@ -38,8 +38,7 @@
 
     /// @returns the accessor indices
     utils::Slice<Value const* const> Indices() const {
-        const auto& slice = operands_.Slice();
-        return utils::Slice<Value const* const>(slice.data + 1, slice.len - 1, slice.cap - 1);
+        return operands_.Slice().Offset(1).Reinterpret<Value const* const>();
     }
 
   private:
diff --git a/src/tint/ir/break_if.h b/src/tint/ir/break_if.h
index 9fba486..b673cd8 100644
--- a/src/tint/ir/break_if.h
+++ b/src/tint/ir/break_if.h
@@ -38,8 +38,7 @@
 
     /// @returns the branch arguments
     utils::Slice<Value const* const> Args() const override {
-        const auto& slice = operands_.Slice();
-        return utils::Slice<Value const* const>(slice.data + 1, slice.len - 1, slice.cap - 1);
+        return operands_.Slice().Offset(1).Reinterpret<Value const* const>();
     }
 
     /// @returns the break condition
diff --git a/src/tint/ir/user_call.h b/src/tint/ir/user_call.h
index 0f9b5ea..d165715 100644
--- a/src/tint/ir/user_call.h
+++ b/src/tint/ir/user_call.h
@@ -33,8 +33,7 @@
 
     /// @returns the call arguments
     utils::Slice<Value const* const> Args() const override {
-        const auto& slice = operands_.Slice();
-        return utils::Slice<Value const* const>(slice.data + 1, slice.len - 1, slice.cap - 1);
+        return operands_.Slice().Offset(1).Reinterpret<Value const* const>();
     }
 
     /// @returns the called function name
diff --git a/src/tint/utils/slice.h b/src/tint/utils/slice.h
index 3380d23..ca25949 100644
--- a/src/tint/utils/slice.h
+++ b/src/tint/utils/slice.h
@@ -162,6 +162,26 @@
     /// @return the length of the slice
     size_t Length() const { return len; }
 
+    /// Create a new slice that represents an offset into this slice
+    /// @param offset the number of elements to offset
+    /// @return the new slice
+    Slice<T> Offset(size_t offset) const {
+        if (offset > len) {
+            offset = len;
+        }
+        return Slice(data + offset, len - offset, cap - offset);
+    }
+
+    /// Create a new slice that represents a truncated version of this slice
+    /// @param length the new length
+    /// @return a new slice that is truncated to `length` elements
+    Slice<T> Truncate(size_t length) const {
+        if (length > len) {
+            length = len;
+        }
+        return Slice(data, length, length);
+    }
+
     /// Index operator
     /// @param i the element index. Must be less than `len`.
     /// @returns a reference to the i'th element.
diff --git a/src/tint/utils/slice_test.cc b/src/tint/utils/slice_test.cc
index 319b678..5725870 100644
--- a/src/tint/utils/slice_test.cc
+++ b/src/tint/utils/slice_test.cc
@@ -142,5 +142,44 @@
     }
 }
 
+TEST(TintSliceTest, Offset) {
+    int elements[] = {1, 2, 3};
+
+    auto slice = Slice{elements};
+    auto offset = slice.Offset(1);
+    EXPECT_EQ(offset.Length(), 2u);
+    EXPECT_EQ(offset[0], 2);
+    EXPECT_EQ(offset[1], 3);
+}
+
+TEST(TintSliceTest, Offset_PastEnd) {
+    int elements[] = {1, 2, 3};
+
+    auto slice = Slice{elements};
+    auto offset = slice.Offset(4);
+    EXPECT_EQ(offset.Length(), 0u);
+}
+
+TEST(TintSliceTest, Truncate) {
+    int elements[] = {1, 2, 3};
+
+    auto slice = Slice{elements};
+    auto truncated = slice.Truncate(2);
+    EXPECT_EQ(truncated.Length(), 2u);
+    EXPECT_EQ(truncated[0], 1);
+    EXPECT_EQ(truncated[1], 2);
+}
+
+TEST(TintSliceTest, Truncate_PastEnd) {
+    int elements[] = {1, 2, 3};
+
+    auto slice = Slice{elements};
+    auto truncated = slice.Truncate(4);
+    EXPECT_EQ(truncated.Length(), 3u);
+    EXPECT_EQ(truncated[0], 1);
+    EXPECT_EQ(truncated[1], 2);
+    EXPECT_EQ(truncated[2], 3);
+}
+
 }  // namespace
 }  // namespace tint::utils