diff --git a/move-stdlib/doc/vector.md b/move-stdlib/doc/vector.md index d600c933f..1c0e6367e 100644 --- a/move-stdlib/doc/vector.md +++ b/move-stdlib/doc/vector.md @@ -63,6 +63,9 @@ the return on investment didn't seem worth it for these simple functions. - [Function `any`](#0x1_vector_any) - [Function `all`](#0x1_vector_all) - [Function `destroy`](#0x1_vector_destroy) +- [Function `range`](#0x1_vector_range) +- [Function `range_with_step`](#0x1_vector_range_with_step) +- [Function `slice`](#0x1_vector_slice) - [Specification](#@Specification_1) - [Helper Functions](#@Helper_Functions_2) - [Function `singleton`](#@Specification_1_singleton) @@ -112,6 +115,26 @@ The index into the vector is out of bounds + + +The range in slice is invalid. + + +
const EINVALID_SLICE_RANGE: u64 = 131076;
+
+ + + + + +The step provided in range is invalid, must be greater than zero. + + +
const EINVALID_STEP: u64 = 131075;
+
+ + + The length of the vectors are not equal. @@ -1580,6 +1603,96 @@ when used in the context of destroying a vector. + + + + +## Function `range` + + + +
public fun range(start: u64, end: u64): vector<u64>
+
+ + + +
+Implementation + + +
public fun range(start: u64, end: u64): vector<u64> {
+    range_with_step(start, end, 1)
+}
+
+ + + +
+ + + +## Function `range_with_step` + + + +
public fun range_with_step(start: u64, end: u64, step: u64): vector<u64>
+
+ + + +
+Implementation + + +
public fun range_with_step(start: u64, end: u64, step: u64): vector<u64> {
+    assert!(step > 0, EINVALID_STEP);
+
+    let vec = vector[];
+    while (start < end) {
+        push_back(&mut vec, start);
+        start = start + step;
+    };
+    vec
+}
+
+ + + +
+ + + +## Function `slice` + + + +
public fun slice<Element: copy>(v: &vector<Element>, start: u64, end: u64): vector<Element>
+
+ + + +
+Implementation + + +
public fun slice<Element: copy>(
+    v: &vector<Element>,
+    start: u64,
+    end: u64
+): vector<Element> {
+    assert!(start <= end && end <= length(v), EINVALID_SLICE_RANGE);
+
+    let vec = vector[];
+    while (start < end) {
+        push_back(&mut vec, *borrow(v, start));
+        start = start + 1;
+    };
+    vec
+}
+
+ + +
diff --git a/move-stdlib/sources/vector.move b/move-stdlib/sources/vector.move index 885737608..05368acf4 100644 --- a/move-stdlib/sources/vector.move +++ b/move-stdlib/sources/vector.move @@ -18,6 +18,12 @@ module std::vector { /// The length of the vectors are not equal. const EVECTORS_LENGTH_MISMATCH: u64 = 0x20002; + /// The step provided in `range` is invalid, must be greater than zero. + const EINVALID_STEP: u64 = 0x20003; + + /// The range in `slice` is invalid. + const EINVALID_SLICE_RANGE: u64 = 0x20004; + #[bytecode_instruction] /// Create an empty vector. native public fun empty(): vector; @@ -589,6 +595,36 @@ module std::vector { for_each_reverse(v, |e| d(e)) } + public fun range(start: u64, end: u64): vector { + range_with_step(start, end, 1) + } + + public fun range_with_step(start: u64, end: u64, step: u64): vector { + assert!(step > 0, EINVALID_STEP); + + let vec = vector[]; + while (start < end) { + push_back(&mut vec, start); + start = start + step; + }; + vec + } + + public fun slice( + v: &vector, + start: u64, + end: u64 + ): vector { + assert!(start <= end && end <= length(v), EINVALID_SLICE_RANGE); + + let vec = vector[]; + while (start < end) { + push_back(&mut vec, *borrow(v, start)); + start = start + 1; + }; + vec + } + // ================================================================= // Module Specification diff --git a/move-stdlib/tests/vector_tests.move b/move-stdlib/tests/vector_tests.move index 8d12fe18a..b8c9e19a4 100644 --- a/move-stdlib/tests/vector_tests.move +++ b/move-stdlib/tests/vector_tests.move @@ -888,6 +888,64 @@ module std::vector_tests { vector::insert(&mut v,6, 6); } + #[test] + fun test_range() { + let result = vector::range(5, 10); + assert!(result == vector[5, 6, 7, 8, 9], 1); + } + + #[test] + fun test_range_with_step() { + let result = vector::range_with_step(0, 10, 2); + assert!(result == vector[0, 2, 4, 6, 8], 1); + + let empty_result = vector::range_with_step(10, 10, 2); + assert!(empty_result == vector[], 1); + + // Test with `start` greater than `end` + let reverse_result = vector::range_with_step(10, 0, 2); + assert!(reverse_result == vector[], 1); + } + + #[test] + #[expected_failure(abort_code = V::EINVALID_STEP)] + fun test_range_with_invalid_step() { + vector::range_with_step(0, 10, 0); + } + + #[test] + fun test_slice() { + let v = &vector[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + + let slice_beginning = vector::slice(v, 0, 3); + assert!(slice_beginning == vector[0, 1, 2], 1); + + let slice_end = vector::slice(v, 7, 10); + assert!(slice_end == vector[7, 8, 9], 1); + + let empty_slice = vector::slice(v, 5, 5); + assert!(empty_slice == vector[], 1); + let empty_slice = vector::slice(v, 0, 0); + assert!(empty_slice == vector[], 1); + + let full_slice = &vector::slice(v, 0, 10); + assert!(full_slice == v, 1); + } + + #[test] + #[expected_failure(abort_code = V::EINVALID_SLICE_RANGE)] + fun test_slice_invalid_range() { + let v = &vector[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + vector::slice(v, 7, 6); // start is greater than end + } + + #[test] + #[expected_failure(abort_code = V::EINVALID_SLICE_RANGE)] + fun test_slice_out_of_bounds() { + let v = &vector[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + vector::slice(v, 0, 11); // end is out of bounds + } + #[test_only] struct MoveOnly {}