Skip to content

Commit

Permalink
[move][stdlib] Add vector::split_off and vector::remove library methods
Browse files Browse the repository at this point in the history
  • Loading branch information
igor-aptos committed Oct 3, 2024
1 parent 06d6cb3 commit 0d2ea8f
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 0 deletions.
69 changes: 69 additions & 0 deletions aptos-move/framework/move-stdlib/doc/vector.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ the return on investment didn't seem worth it for these simple functions.
- [Function `reverse_slice`](#0x1_vector_reverse_slice)
- [Function `append`](#0x1_vector_append)
- [Function `reverse_append`](#0x1_vector_reverse_append)
- [Function `split_off`](#0x1_vector_split_off)
- [Function `trim`](#0x1_vector_trim)
- [Function `trim_reverse`](#0x1_vector_trim_reverse)
- [Function `is_empty`](#0x1_vector_is_empty)
Expand All @@ -39,6 +40,7 @@ the return on investment didn't seem worth it for these simple functions.
- [Function `remove`](#0x1_vector_remove)
- [Function `remove_value`](#0x1_vector_remove_value)
- [Function `swap_remove`](#0x1_vector_swap_remove)
- [Function `replace`](#0x1_vector_replace)
- [Function `for_each`](#0x1_vector_for_each)
- [Function `for_each_reverse`](#0x1_vector_for_each_reverse)
- [Function `for_each_ref`](#0x1_vector_for_each_ref)
Expand Down Expand Up @@ -481,6 +483,42 @@ Pushes all of the elements of the <code>other</code> vector into the <code>self<



</details>

<a id="0x1_vector_split_off"></a>

## Function `split_off`

Splits the collection into two at the given index.
Returns a newly allocated vector containing the elements in the range [at, len).
After the call, the original vector will be left containing the elements [0, at)
with its previous capacity unchanged.


<pre><code><b>public</b> <b>fun</b> <a href="vector.md#0x1_vector_split_off">split_off</a>&lt;Element&gt;(self: &<b>mut</b> <a href="vector.md#0x1_vector">vector</a>&lt;Element&gt;, at: u64): <a href="vector.md#0x1_vector">vector</a>&lt;Element&gt;
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="vector.md#0x1_vector_split_off">split_off</a>&lt;Element&gt;(self: &<b>mut</b> <a href="vector.md#0x1_vector">vector</a>&lt;Element&gt;, at: u64): <a href="vector.md#0x1_vector">vector</a>&lt;Element&gt; {
<b>let</b> len = <a href="vector.md#0x1_vector_length">length</a>(self);
<b>assert</b>!(at &lt;= len, <a href="vector.md#0x1_vector_EINDEX_OUT_OF_BOUNDS">EINDEX_OUT_OF_BOUNDS</a>);
<b>let</b> other = <a href="vector.md#0x1_vector_empty">empty</a>();
<b>while</b> (len &gt; at) {
<a href="vector.md#0x1_vector_push_back">push_back</a>(&<b>mut</b> other, <a href="vector.md#0x1_vector_pop_back">pop_back</a>(self));
len = len - 1;
};
<a href="vector.md#0x1_vector_reverse">reverse</a>(&<b>mut</b> other);
other
}
</code></pre>



</details>

<a id="0x1_vector_trim"></a>
Expand Down Expand Up @@ -800,6 +838,37 @@ Aborts if <code>i</code> is out of bounds.



</details>

<a id="0x1_vector_replace"></a>

## Function `replace`

Replace the <code>i</code>th element of the vector <code>self</code> with the given value, and return
to the caller the value that was there before.
Aborts if <code>i</code> is out of bounds.


<pre><code><b>public</b> <b>fun</b> <a href="vector.md#0x1_vector_replace">replace</a>&lt;Element&gt;(self: &<b>mut</b> <a href="vector.md#0x1_vector">vector</a>&lt;Element&gt;, i: u64, val: Element): Element
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="vector.md#0x1_vector_replace">replace</a>&lt;Element&gt;(self: &<b>mut</b> <a href="vector.md#0x1_vector">vector</a>&lt;Element&gt;, i: u64, val: Element): Element {
<b>let</b> last_idx = <a href="vector.md#0x1_vector_length">length</a>(self);
<b>assert</b>!(i &lt; last_idx, <a href="vector.md#0x1_vector_EINDEX_OUT_OF_BOUNDS">EINDEX_OUT_OF_BOUNDS</a>);
<a href="vector.md#0x1_vector_push_back">push_back</a>(self, val);
<a href="vector.md#0x1_vector_swap">swap</a>(self, i, last_idx);
<a href="vector.md#0x1_vector_pop_back">pop_back</a>(self)
}
</code></pre>



</details>

<a id="0x1_vector_for_each"></a>
Expand Down
27 changes: 27 additions & 0 deletions aptos-move/framework/move-stdlib/sources/vector.move
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,22 @@ module std::vector {
pragma intrinsic = true;
}

/// Splits the collection into two at the given index.
/// Returns a newly allocated vector containing the elements in the range [at, len).
/// After the call, the original vector will be left containing the elements [0, at)
/// with its previous capacity unchanged.
public fun split_off<Element>(self: &mut vector<Element>, at: u64): vector<Element> {
let len = length(self);
assert!(at <= len, EINDEX_OUT_OF_BOUNDS);
let other = empty();
while (len > at) {
push_back(&mut other, pop_back(self));
len = len - 1;
};
reverse(&mut other);
other
}

/// Trim a vector to a smaller size, returning the evicted elements in order
public fun trim<Element>(self: &mut vector<Element>, new_len: u64): vector<Element> {
let res = trim_reverse(self, new_len);
Expand Down Expand Up @@ -266,6 +282,17 @@ module std::vector {
pragma intrinsic = true;
}

/// Replace the `i`th element of the vector `self` with the given value, and return
/// to the caller the value that was there before.
/// Aborts if `i` is out of bounds.
public fun replace<Element>(self: &mut vector<Element>, i: u64, val: Element): Element {
let last_idx = length(self);
assert!(i < last_idx, EINDEX_OUT_OF_BOUNDS);
push_back(self, val);
swap(self, i, last_idx);
pop_back(self)
}

/// Apply the function to each element in the vector, consuming it.
public inline fun for_each<Element>(self: vector<Element>, f: |Element|) {
reverse(&mut self); // We need to reverse the vector to consume it efficiently
Expand Down
35 changes: 35 additions & 0 deletions aptos-move/framework/move-stdlib/tests/vector_tests.move
Original file line number Diff line number Diff line change
Expand Up @@ -954,4 +954,39 @@ module std::vector_tests {
let v = vector[MoveOnly {}];
vector::destroy(v, |m| { let MoveOnly {} = m; })
}

#[test]
#[expected_failure(abort_code = V::EINDEX_OUT_OF_BOUNDS)]
fun test_replace_empty_abort() {
let v = vector[];
let MoveOnly {} = vector::replace(&mut v, 0, MoveOnly {});
vector::destroy_empty(v);
}

#[test]
fun test_replace() {
let v = vector[1, 2, 3, 4];
vector::replace(&mut v, 1, 17);
assert!(v == vector[1, 17, 3, 4], 0);
}

#[test]
fun test_split_off() {
let v = vector[1, 2, 3, 4, 5, 6];
let other = vector::split_off(&mut v, 4);
assert!(v == vector[1, 2, 3, 4], 0);
assert!(other == vector[5, 6], 1);

let other_empty = vector::split_off(&mut v, 4);
assert!(v == vector[1, 2, 3, 4], 2);
assert!(other_empty == vector[], 3);

}

#[test]
#[expected_failure(abort_code = V::EINDEX_OUT_OF_BOUNDS)]
fun test_split_off_abort() {
let v = vector[1, 2, 3];
vector::split_off(&mut v, 4);
}
}

0 comments on commit 0d2ea8f

Please sign in to comment.