Skip to content

Commit 19d72b0

Browse files
WayneAlamnn
andauthored
[sui-framework] Added swap and swap_remove function to the table_vec.move (#13644)
## Description Added `swap_remove` function to `table_vec.move` since we have a situation to remove an certain element in the `TableVec` and both `table` and `vector` have similar functionality implemented. ## Test Plan New unit tests for `sui::table_vec`. --- If your changes are not user-facing and not a breaking change, you can skip the following section. Otherwise, please indicate what changed, and then add to the Release Notes section as highlighted during the release process. ### Type of Change (Check all that apply) - [x] protocol change - [x] user-visible impact - [ ] breaking change for a client SDKs - [x] breaking change for FNs (FN binary must upgrade) - [x] breaking change for validators or node operators (must upgrade binaries) - [ ] breaking change for on-chain data layout - [ ] necessitate either a data wipe or data migration ### Release notes Introduces protocol version 25 which adds `sui::table_vec::swap` and `sui::table_vec::swap_remove` to system packages. Use these functions to swap two positions in a single `TableVec<T>` or swap an element to the end and remove it in `O(1)` time, analogous to `std::vector::swap` and `std::vector::swap_remove`. --------- Co-authored-by: Ashok Menon <[email protected]>
1 parent 24fadbe commit 19d72b0

File tree

2 files changed

+61
-3
lines changed

2 files changed

+61
-3
lines changed

crates/sui-framework/packages/sui-framework/sources/table_vec.move

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,25 @@ module sui::table_vec {
8181
table::drop(contents)
8282
}
8383

84+
/// Swaps the elements at the `i`th and `j`th indices in the TableVec `t`.
85+
/// Aborts if `i` or `j` is out of bounds.
86+
public fun swap<Element: store>(t: &mut TableVec<Element>, i: u64, j: u64) {
87+
assert!(length(t) > i, EIndexOutOfBound);
88+
assert!(length(t) > j, EIndexOutOfBound);
89+
if (i == j) { return };
90+
let element_i = table::remove(&mut t.contents, i);
91+
let element_j = table::remove(&mut t.contents, j);
92+
table::add(&mut t.contents, j, element_i);
93+
table::add(&mut t.contents, i, element_j);
94+
}
95+
96+
/// Swap the `i`th element of the TableVec `t` with the last element and then pop the TableVec.
97+
/// This is O(1), but does not preserve ordering of elements in the TableVec.
98+
/// Aborts if `i` is out of bounds.
99+
public fun swap_remove<Element: store>(t: &mut TableVec<Element>, i: u64): Element {
100+
assert!(length(t) > i, EIndexOutOfBound);
101+
let last_idx = length(t) - 1;
102+
swap(t, i, last_idx);
103+
pop_back(t)
104+
}
84105
}

crates/sui-framework/packages/sui-framework/tests/table_vec_tests.move

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ module sui::table_vec_tests {
1010

1111
#[test]
1212
fun simple_all_functions() {
13-
let scenario = ts::begin(TEST_SENDER_ADDR);
13+
let scenario = ts::begin(TEST_SENDER_ADDR);
1414

1515
let table_vec = table_vec::empty<u64>(ts::ctx(&mut scenario));
1616
assert!(table_vec::length(&table_vec) == 0, 0);
@@ -21,7 +21,14 @@ module sui::table_vec_tests {
2121
let value = table_vec::borrow(&table_vec, 0);
2222
assert!(*value == 8, 0);
2323

24-
table_vec::pop_back(&mut table_vec);
24+
table_vec::push_back(&mut table_vec, 5);
25+
table_vec::swap(&mut table_vec, 0, 1);
26+
27+
let value = table_vec::swap_remove(&mut table_vec, 0);
28+
assert!(value == 5, 0);
29+
30+
let value = table_vec::pop_back(&mut table_vec);
31+
assert!(value == 8, 0);
2532
table_vec::destroy_empty(table_vec);
2633
ts::end(scenario);
2734
}
@@ -41,7 +48,7 @@ module sui::table_vec_tests {
4148
let scenario = ts::begin(TEST_SENDER_ADDR);
4249
let table_vec = table_vec::empty<u64>(ts::ctx(&mut scenario));
4350
table_vec::pop_back(&mut table_vec);
44-
table_vec::destroy_empty(table_vec);
51+
table_vec::destroy_empty(table_vec);
4552
ts::end(scenario);
4653
}
4754

@@ -64,4 +71,34 @@ module sui::table_vec_tests {
6471
table_vec::destroy_empty(table_vec);
6572
ts::end(scenario);
6673
}
74+
75+
#[test]
76+
#[expected_failure(abort_code = sui::table_vec::EIndexOutOfBound)]
77+
fun swap_out_of_bounds_aborts() {
78+
let scenario = ts::begin(TEST_SENDER_ADDR);
79+
let table_vec = table_vec::singleton(1, ts::ctx(&mut scenario));
80+
table_vec::swap(&mut table_vec, 0, 77);
81+
table_vec::destroy_empty(table_vec);
82+
ts::end(scenario);
83+
}
84+
85+
#[test]
86+
fun swap_same_index_succeeds() {
87+
let scenario = ts::begin(TEST_SENDER_ADDR);
88+
let table_vec = table_vec::singleton(1, ts::ctx(&mut scenario));
89+
table_vec::swap(&mut table_vec, 0, 0);
90+
table_vec::pop_back(&mut table_vec);
91+
table_vec::destroy_empty(table_vec);
92+
ts::end(scenario);
93+
}
94+
95+
#[test]
96+
#[expected_failure(abort_code = sui::table_vec::EIndexOutOfBound)]
97+
fun swap_same_index_out_of_bounds_aborts() {
98+
let scenario = ts::begin(TEST_SENDER_ADDR);
99+
let table_vec = table_vec::singleton(1, ts::ctx(&mut scenario));
100+
table_vec::swap(&mut table_vec, 77, 77);
101+
table_vec::destroy_empty(table_vec);
102+
ts::end(scenario);
103+
}
67104
}

0 commit comments

Comments
 (0)