Skip to content

Commit

Permalink
[move] Add do and range_do macros for u* (MystenLabs#18187)
Browse files Browse the repository at this point in the history
## Description 

- Added do, do_eq, range_do, and range_do_eq macros for integer types

## Test plan 

- Added tests

---

## Release notes

Check each box that your changes affect. If none of the boxes relate to
your changes, release notes aren't required.

For each box you select, include information after the relevant heading
that describes the impact of your changes that a user might notice and
any actions they must take to implement updates.

- [ ] Protocol: 
- [ ] Nodes (Validators and Full nodes): 
- [ ] Indexer: 
- [ ] JSON-RPC: 
- [ ] GraphQL: 
- [ ] CLI: 
- [ ] Rust SDK:
  • Loading branch information
tnowacki authored Jun 11, 2024
1 parent 89db5e1 commit 738c473
Show file tree
Hide file tree
Showing 14 changed files with 242 additions and 0 deletions.
32 changes: 32 additions & 0 deletions crates/sui-framework/packages/move-stdlib/sources/macros.move
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,36 @@ module std::macros {

res as $T
}

public(package) macro fun range_do($start: _, $stop: _, $f: |_|) {
let mut i = $start;
let stop = $stop;
while (i < stop) {
$f(i);
i = i + 1;
}
}

public(package) macro fun range_do_eq($start: _, $stop: _, $f: |_|) {
let mut i = $start;
let stop = $stop;
// we check `i >= stop` inside the loop instead of `i <= stop` as `while` condition to avoid
// incrementing `i` past the MAX integer value.
// Because of this, we need to check if `i > stop` and return early--instead of letting the
// loop bound handle it, like in the `range_do` macro.
if (i > stop) return;
loop {
$f(i);
if (i >= stop) break;
i = i + 1;
}
}

public(package) macro fun do($stop: _, $f: |_|) {
range_do!(0, $stop, $f)
}

public(package) macro fun do_eq($stop: _, $f: |_|) {
range_do_eq!(0, $stop, $f)
}
}
20 changes: 20 additions & 0 deletions crates/sui-framework/packages/move-stdlib/sources/u128.move
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,24 @@ module std::u128 {
public fun sqrt(x: u128): u128 {
std::macros::num_sqrt!<u128, u256>(x, 128)
}

/// Loops applying `$f` to each number from `$start` to `$stop` (exclusive)
public macro fun range_do($start: u128, $stop: u128, $f: |u128|) {
std::macros::range_do!($start, $stop, $f)
}

/// Loops applying `$f` to each number from `$start` to `$stop` (inclusive)
public macro fun range_do_eq($start: u128, $stop: u128, $f: |u128|) {
std::macros::range_do_eq!($start, $stop, $f)
}

/// Loops applying `$f` to each number from `0` to `$stop` (exclusive)
public macro fun do($stop: u128, $f: |u128|) {
std::macros::do!($stop, $f)
}

/// Loops applying `$f` to each number from `0` to `$stop` (inclusive)
public macro fun do_eq($stop: u128, $f: |u128|) {
std::macros::do_eq!($stop, $f)
}
}
20 changes: 20 additions & 0 deletions crates/sui-framework/packages/move-stdlib/sources/u16.move
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,24 @@ module std::u16 {
public fun sqrt(x: u16): u16 {
std::macros::num_sqrt!<u16, u32>(x, 16)
}

/// Loops applying `$f` to each number from `$start` to `$stop` (exclusive)
public macro fun range_do($start: u16, $stop: u16, $f: |u16|) {
std::macros::range_do!($start, $stop, $f)
}

/// Loops applying `$f` to each number from `$start` to `$stop` (inclusive)
public macro fun range_do_eq($start: u16, $stop: u16, $f: |u16|) {
std::macros::range_do_eq!($start, $stop, $f)
}

/// Loops applying `$f` to each number from `0` to `$stop` (exclusive)
public macro fun do($stop: u16, $f: |u16|) {
std::macros::do!($stop, $f)
}

/// Loops applying `$f` to each number from `0` to `$stop` (inclusive)
public macro fun do_eq($stop: u16, $f: |u16|) {
std::macros::do_eq!($stop, $f)
}
}
20 changes: 20 additions & 0 deletions crates/sui-framework/packages/move-stdlib/sources/u256.move
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,24 @@ module std::u256 {
public fun pow(base: u256, exponent: u8): u256 {
std::macros::num_pow!(base, exponent)
}

/// Loops applying `$f` to each number from `$start` to `$stop` (exclusive)
public macro fun range_do($start: u256, $stop: u256, $f: |u256|) {
std::macros::range_do!($start, $stop, $f)
}

/// Loops applying `$f` to each number from `$start` to `$stop` (inclusive)
public macro fun range_do_eq($start: u256, $stop: u256, $f: |u256|) {
std::macros::range_do_eq!($start, $stop, $f)
}

/// Loops applying `$f` to each number from `0` to `$stop` (exclusive)
public macro fun do($stop: u256, $f: |u256|) {
std::macros::do!($stop, $f)
}

/// Loops applying `$f` to each number from `0` to `$stop` (inclusive)
public macro fun do_eq($stop: u256, $f: |u256|) {
std::macros::do_eq!($stop, $f)
}
}
20 changes: 20 additions & 0 deletions crates/sui-framework/packages/move-stdlib/sources/u32.move
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,24 @@ module std::u32 {
public fun sqrt(x: u32): u32 {
std::macros::num_sqrt!<u32, u64>(x, 32)
}

/// Loops applying `$f` to each number from `$start` to `$stop` (exclusive)
public macro fun range_do($start: u32, $stop: u32, $f: |u32|) {
std::macros::range_do!($start, $stop, $f)
}

/// Loops applying `$f` to each number from `$start` to `$stop` (inclusive)
public macro fun range_do_eq($start: u32, $stop: u32, $f: |u32|) {
std::macros::range_do_eq!($start, $stop, $f)
}

/// Loops applying `$f` to each number from `0` to `$stop` (exclusive)
public macro fun do($stop: u32, $f: |u32|) {
std::macros::do!($stop, $f)
}

/// Loops applying `$f` to each number from `0` to `$stop` (inclusive)
public macro fun do_eq($stop: u32, $f: |u32|) {
std::macros::do_eq!($stop, $f)
}
}
20 changes: 20 additions & 0 deletions crates/sui-framework/packages/move-stdlib/sources/u64.move
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,24 @@ module std::u64 {
public fun sqrt(x: u64): u64 {
std::macros::num_sqrt!<u64, u128>(x, 64)
}

/// Loops applying `$f` to each number from `$start` to `$stop` (exclusive)
public macro fun range_do($start: u64, $stop: u64, $f: |u64|) {
std::macros::range_do!($start, $stop, $f)
}

/// Loops applying `$f` to each number from `$start` to `$stop` (inclusive)
public macro fun range_do_eq($start: u64, $stop: u64, $f: |u64|) {
std::macros::range_do_eq!($start, $stop, $f)
}

/// Loops applying `$f` to each number from `0` to `$stop` (exclusive)
public macro fun do($stop: u64, $f: |u64|) {
std::macros::do!($stop, $f)
}

/// Loops applying `$f` to each number from `0` to `$stop` (inclusive)
public macro fun do_eq($stop: u64, $f: |u64|) {
std::macros::do_eq!($stop, $f)
}
}
20 changes: 20 additions & 0 deletions crates/sui-framework/packages/move-stdlib/sources/u8.move
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,24 @@ module std::u8 {
public fun sqrt(x: u8): u8 {
std::macros::num_sqrt!<u8, u16>(x, 8)
}

/// Loops applying `$f` to each number from `$start` to `$stop` (exclusive)
public macro fun range_do($start: u8, $stop: u8, $f: |u8|) {
std::macros::range_do!($start, $stop, $f)
}

/// Loops applying `$f` to each number from `$start` to `$stop` (inclusive)
public macro fun range_do_eq($start: u8, $stop: u8, $f: |u8|) {
std::macros::range_do_eq!($start, $stop, $f)
}

/// Loops applying `$f` to each number from `0` to `$stop` (exclusive)
public macro fun do($stop: u8, $f: |u8|) {
std::macros::do!($stop, $f)
}

/// Loops applying `$f` to each number from `0` to `$stop` (inclusive)
public macro fun do_eq($stop: u8, $f: |u8|) {
std::macros::do_eq!($stop, $f)
}
}
55 changes: 55 additions & 0 deletions crates/sui-framework/packages/move-stdlib/tests/integer_tests.move
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,62 @@ module std::integer_tests {
i = i + 1;
}
}
}

public(package) macro fun sum_range<$T>($n: $T): $T {
let n = $n;
(n * (n + 1)) / 2
}

public(package) macro fun test_dos_case<$T>($case: $T) {
let case = $case;
let mut sum: $T = 0;
case.do!(|i| sum = sum + i);
assert_eq!(sum, sum_range!(case - 1));

sum = 0;
case.do_eq!(|i| sum = sum + i);
assert_eq!(sum, sum_range!(case));

let half = case / 2;

sum = 0;
half.range_do!(case, |i| sum = sum + i);
assert_eq!(sum, sum_range!(case - 1) - sum_range!(half - 1));

sum = 0;
half.range_do_eq!(case, |i| sum = sum + i);
assert_eq!(sum, sum_range!(case) - sum_range!(half - 1));
}

public(package) macro fun test_dos<$T>($max: $T, $cases: vector<$T>) {
let max = $max;
let cases = $cases;
// test bounds/invalid ranges
(0: $T).do!(|_| assert!(false));
cases!(max, cases, |case_pred, case, case_succ| {
if (case == 0) return;
case.range_do!(0, |_| assert!(false));
case.range_do_eq!(0, |_| assert!(false));

if (case == max) return;
case.range_do!(case_pred, |_| assert!(false));
case_succ.range_do!(case, |_| assert!(false));
case.range_do_eq!(case_pred, |_| assert!(false));
case_succ.range_do_eq!(case, |_| assert!(false));
});

// test upper bound being max
let max_pred = max - 1;
max_pred.range_do_eq!(max, |_| ());

// test iteration numbers
let cases: vector<$T> = vector[3, 5, 8, 11, 14];
cases!(max, cases, |case_pred, case, case_succ| {
test_dos_case!(case_pred);
test_dos_case!(case);
test_dos_case!(case_succ);
});
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,9 @@ module std::u128_tests {
vector[0, 2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53, 56, 59];
integer_tests::test_sqrt!(MAX, CASES, reflexive_cases)
}

#[test]
fun test_dos() {
integer_tests::test_dos!(MAX, CASES);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,9 @@ module std::u16_tests {
vector[0, 2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53, 56, 59];
integer_tests::test_sqrt!(MAX, CASES, reflexive_cases)
}

#[test]
fun test_dos() {
integer_tests::test_dos!(MAX, CASES);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,9 @@ module std::u256_tests {
fun test_pow_overflow() {
255u256.pow(255);
}

#[test]
fun test_dos() {
integer_tests::test_dos!(MAX, CASES);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,9 @@ module std::u32_tests {
vector[0, 2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53, 56, 59];
integer_tests::test_sqrt!(MAX, CASES, reflexive_cases)
}

#[test]
fun test_dos() {
integer_tests::test_dos!(MAX, CASES);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,10 @@ module std::u64_tests {
vector[0, 2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53, 56, 59];
integer_tests::test_sqrt!(MAX, CASES, reflexive_cases)
}

#[test]
fun test_dos() {
integer_tests::test_dos!(MAX, CASES);
}

}
9 changes: 9 additions & 0 deletions crates/sui-framework/packages/move-stdlib/tests/u8_tests.move
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#[test_only]
module std::u8_tests {
use std::integer_tests;
use std::unit_test::assert_eq;

const BIT_SIZE: u8 = 8;
const MAX: u8 = 0xFF;
Expand Down Expand Up @@ -65,4 +66,12 @@ module std::u8_tests {
fun test_sqrt() {
integer_tests::test_sqrt!(MAX, CASES, vector[0, 2, 5, 8, 11, 14]);
}

#[test]
fun test_dos() {
let mut sum = 0u16;
255u8.do_eq!(|i| sum = sum + (i as u16));
assert_eq!(sum, 32640);
integer_tests::test_dos!(MAX, CASES);
}
}

0 comments on commit 738c473

Please sign in to comment.