Skip to content

Commit

Permalink
[move] Implement generic comparison method in move - move part
Browse files Browse the repository at this point in the history
  • Loading branch information
igor-aptos committed Nov 8, 2024
1 parent 686d2de commit 3e9fb56
Show file tree
Hide file tree
Showing 7 changed files with 395 additions and 8 deletions.
235 changes: 235 additions & 0 deletions aptos-move/framework/move-stdlib/doc/cmp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@

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

# Module `0x1::cmp`



- [Enum `Ordering`](#0x1_cmp_Ordering)
- [Function `compare`](#0x1_cmp_compare)
- [Function `is_eq`](#0x1_cmp_is_eq)
- [Function `is_lt`](#0x1_cmp_is_lt)
- [Function `is_le`](#0x1_cmp_is_le)
- [Function `is_gt`](#0x1_cmp_is_gt)
- [Function `is_ge`](#0x1_cmp_is_ge)


<pre><code></code></pre>



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

## Enum `Ordering`



<pre><code>enum <a href="cmp.md#0x1_cmp_Ordering">Ordering</a> <b>has</b> <b>copy</b>, drop
</code></pre>



<details>
<summary>Variants</summary>


<details>
<summary>Less</summary>


<details>
<summary>Fields</summary>


<dl>
</dl>


</details>

</details>

<details>
<summary>Equal</summary>


<details>
<summary>Fields</summary>


<dl>
</dl>


</details>

</details>

<details>
<summary>Greater</summary>


<details>
<summary>Fields</summary>


<dl>
</dl>


</details>

</details>

</details>

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

## Function `compare`

Compares two values with the natural ordering:
- native types are compared identically to <code>&lt;</code> and other operators
- complex types
- Structs and vectors - are compared lexicographically - first field/element is compared first,
and if equal we proceed to the next.
- enum's are compared first by their variant, and if equal - they are compared as structs are.


<pre><code><b>public</b>(<b>friend</b>) <b>fun</b> <a href="cmp.md#0x1_cmp_compare">compare</a>&lt;T&gt;(first: &T, second: &T): <a href="cmp.md#0x1_cmp_Ordering">cmp::Ordering</a>
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>native</b> <b>public</b>(<b>friend</b>) <b>fun</b> <a href="cmp.md#0x1_cmp_compare">compare</a>&lt;T&gt;(first: &T, second: &T): <a href="cmp.md#0x1_cmp_Ordering">Ordering</a>;
</code></pre>



</details>

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

## Function `is_eq`



<pre><code><b>public</b> <b>fun</b> <a href="cmp.md#0x1_cmp_is_eq">is_eq</a>(self: &<a href="cmp.md#0x1_cmp_Ordering">cmp::Ordering</a>): bool
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="cmp.md#0x1_cmp_is_eq">is_eq</a>(self: &<a href="cmp.md#0x1_cmp_Ordering">Ordering</a>): bool {
self is Ordering::Equal
}
</code></pre>



</details>

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

## Function `is_lt`



<pre><code><b>public</b> <b>fun</b> <a href="cmp.md#0x1_cmp_is_lt">is_lt</a>(self: &<a href="cmp.md#0x1_cmp_Ordering">cmp::Ordering</a>): bool
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="cmp.md#0x1_cmp_is_lt">is_lt</a>(self: &<a href="cmp.md#0x1_cmp_Ordering">Ordering</a>): bool {
self is Ordering::Less
}
</code></pre>



</details>

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

## Function `is_le`



<pre><code><b>public</b> <b>fun</b> <a href="cmp.md#0x1_cmp_is_le">is_le</a>(self: &<a href="cmp.md#0x1_cmp_Ordering">cmp::Ordering</a>): bool
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="cmp.md#0x1_cmp_is_le">is_le</a>(self: &<a href="cmp.md#0x1_cmp_Ordering">Ordering</a>): bool {
!(self is Ordering::Greater)
}
</code></pre>



</details>

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

## Function `is_gt`



<pre><code><b>public</b> <b>fun</b> <a href="cmp.md#0x1_cmp_is_gt">is_gt</a>(self: &<a href="cmp.md#0x1_cmp_Ordering">cmp::Ordering</a>): bool
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="cmp.md#0x1_cmp_is_gt">is_gt</a>(self: &<a href="cmp.md#0x1_cmp_Ordering">Ordering</a>): bool {
self is Ordering::Greater
}
</code></pre>



</details>

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

## Function `is_ge`



<pre><code><b>public</b> <b>fun</b> <a href="cmp.md#0x1_cmp_is_ge">is_ge</a>(self: &<a href="cmp.md#0x1_cmp_Ordering">cmp::Ordering</a>): bool
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="cmp.md#0x1_cmp_is_ge">is_ge</a>(self: &<a href="cmp.md#0x1_cmp_Ordering">Ordering</a>): bool {
!(self is Ordering::Less)
}
</code></pre>



</details>


[move-book]: https://aptos.dev/move/book/SUMMARY
1 change: 1 addition & 0 deletions aptos-move/framework/move-stdlib/doc/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ For on overview of the Move language, see the [Move Book][move-book].
- [`0x1::acl`](acl.md#0x1_acl)
- [`0x1::bcs`](bcs.md#0x1_bcs)
- [`0x1::bit_vector`](bit_vector.md#0x1_bit_vector)
- [`0x1::cmp`](cmp.md#0x1_cmp)
- [`0x1::error`](error.md#0x1_error)
- [`0x1::features`](features.md#0x1_features)
- [`0x1::fixed_point32`](fixed_point32.md#0x1_fixed_point32)
Expand Down
133 changes: 133 additions & 0 deletions aptos-move/framework/move-stdlib/sources/cmp.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
module std::cmp {
enum Ordering has copy, drop {
/// First value is less than the second value.
Less,
/// First value is equal to the second value.
Equal,
/// First value is greater than the second value.
Greater,
}

// TODO - functions here are `public(friend)` here for one release,
// and to be changed to `public` one release later.
#[test_only]
friend std::bcs_tests;

/// Compares two values with the natural ordering:
/// - native types are compared identically to `<` and other operators
/// - complex types
/// - Structs and vectors - are compared lexicographically - first field/element is compared first,
/// and if equal we proceed to the next.
/// - enum's are compared first by their variant, and if equal - they are compared as structs are.
native public(friend) fun compare<T>(first: &T, second: &T): Ordering;

public fun is_eq(self: &Ordering): bool {
self is Ordering::Equal
}

public fun is_lt(self: &Ordering): bool {
self is Ordering::Less
}

public fun is_le(self: &Ordering): bool {
!(self is Ordering::Greater)
}

public fun is_gt(self: &Ordering): bool {
self is Ordering::Greater
}

public fun is_ge(self: &Ordering): bool {
!(self is Ordering::Less)
}

#[test_only]
struct SomeStruct has drop {
field_1: u64,
field_2: u64,
}
#[test_only]
enum SimpleEnum has drop {
V { field: u64 },
}

#[test_only]
enum SomeEnum has drop {
V1 { field_1: u64 },
V2 { field_2: u64 },
V3 { field_3: SomeStruct },
V4 { field_4: vector<u64> },
V5 { field_5: SimpleEnum },
}

#[test]
fun test_compare_numbers() {
assert!(!is_eq(&compare(&1, &5)), 0);
assert!(is_lt(&compare(&1, &5)), 1);
assert!(is_le(&compare(&1, &5)), 2);
assert!(is_eq(&compare(&5, &5)), 3);
assert!(!is_lt(&compare(&5, &5)), 4);
assert!(is_le(&compare(&5, &5)), 5);
assert!(!is_eq(&compare(&7, &5)), 6);
assert!(!is_lt(&compare(&7, &5)), 7);
assert!(!is_le(&compare(&7, &5)), 8);

assert!(!compare(&1, &5).is_eq(), 0);
assert!(compare(&1, &5).is_lt(), 1);
assert!(compare(&1, &5).is_le(), 2);
assert!(compare(&5, &5).is_eq(), 3);
assert!(!compare(&5, &5).is_lt(), 4);
assert!(compare(&5, &5).is_le(), 5);
assert!(!compare(&7, &5).is_eq(), 6);
assert!(!compare(&7, &5).is_lt(), 7);
assert!(!compare(&7, &5).is_le(), 8);
}

#[test]
fun test_compare_vectors() {
let empty = vector[]; // here for typing, for the second line
assert!(compare(&empty, &vector[1] ) is Ordering::Less, 0);
assert!(compare(&empty, &vector[] ) is Ordering::Equal, 1);
assert!(compare(&vector[1], &vector[] ) is Ordering::Greater, 2);
assert!(compare(&vector[1, 2], &vector[1, 2] ) is Ordering::Equal, 3);
assert!(compare(&vector[1, 2, 3], &vector[5] ) is Ordering::Less, 4);
assert!(compare(&vector[1, 2, 3], &vector[5, 6, 7]) is Ordering::Less, 5);
assert!(compare(&vector[1, 2, 3], &vector[1, 2, 7]) is Ordering::Less, 6);
}

#[test]
fun test_compare_structs() {
assert!(compare(&SomeStruct { field_1: 1, field_2: 2}, &SomeStruct { field_1: 1, field_2: 2}) is Ordering::Equal, 0);
assert!(compare(&SomeStruct { field_1: 1, field_2: 2}, &SomeStruct { field_1: 1, field_2: 3}) is Ordering::Less, 1);
assert!(compare(&SomeStruct { field_1: 1, field_2: 2}, &SomeStruct { field_1: 1, field_2: 1}) is Ordering::Greater, 2);
assert!(compare(&SomeStruct { field_1: 1, field_2: 2}, &SomeStruct { field_1: 1, field_2: 1}) is Ordering::Greater, 3);
}

#[test]
fun test_compare_vector_of_structs() {
assert!(compare(&vector[SomeStruct { field_1: 1, field_2: 2}, SomeStruct { field_1: 3, field_2: 4}], &vector[SomeStruct { field_1: 1, field_2: 3}]) is Ordering::Less, 0);
assert!(compare(&vector[SomeStruct { field_1: 1, field_2: 2}, SomeStruct { field_1: 3, field_2: 4}], &vector[SomeStruct { field_1: 1, field_2: 2}, SomeStruct { field_1: 1, field_2: 3}]) is Ordering::Greater, 1);
}

#[test]
fun test_compare_enums() {
assert!(compare(&SomeEnum::V1 { field_1: 6}, &SomeEnum::V1 { field_1: 6}) is Ordering::Equal, 0);
assert!(compare(&SomeEnum::V1 { field_1: 6}, &SomeEnum::V2 { field_2: 1}) is Ordering::Less, 1);
assert!(compare(&SomeEnum::V1 { field_1: 6}, &SomeEnum::V2 { field_2: 8}) is Ordering::Less, 2);
assert!(compare(&SomeEnum::V1 { field_1: 6}, &SomeEnum::V1 { field_1: 5}) is Ordering::Greater, 3);

assert!(compare(&SomeEnum::V3 { field_3: SomeStruct { field_1: 1, field_2: 2}}, &SomeEnum::V3 { field_3: SomeStruct { field_1: 1, field_2: 2}}) is Ordering::Equal, 4);
assert!(compare(&SomeEnum::V3 { field_3: SomeStruct { field_1: 1, field_2: 2}}, &SomeEnum::V3 { field_3: SomeStruct { field_1: 1, field_2: 3}}) is Ordering::Less, 5);
assert!(compare(&SomeEnum::V3 { field_3: SomeStruct { field_1: 1, field_2: 2}}, &SomeEnum::V3 { field_3: SomeStruct { field_1: 1, field_2: 1}}) is Ordering::Greater, 6);
assert!(compare(&SomeEnum::V3 { field_3: SomeStruct { field_1: 1, field_2: 2}}, &SomeEnum::V3 { field_3: SomeStruct { field_1: 1, field_2: 1}}) is Ordering::Greater, 7);

assert!(compare(&SomeEnum::V4 { field_4: vector[1, 2]}, &SomeEnum::V4 { field_4: vector[1, 2]}) is Ordering::Equal, 8);
assert!(compare(&SomeEnum::V4 { field_4: vector[1, 2, 3]}, &SomeEnum::V4 { field_4: vector[5]}) is Ordering::Less, 9);
assert!(compare(&SomeEnum::V4 { field_4: vector[1, 2, 3]}, &SomeEnum::V4 { field_4: vector[5, 6, 7]}) is Ordering::Less, 10);
assert!(compare(&SomeEnum::V4 { field_4: vector[1, 2, 3]}, &SomeEnum::V4 { field_4: vector[1, 2, 7]}) is Ordering::Less, 11);

assert!(compare(&SomeEnum::V5 { field_5: SimpleEnum::V { field: 3}}, &SomeEnum::V5 { field_5: SimpleEnum::V { field: 3}}) is Ordering::Equal, 12);
assert!(compare(&SomeEnum::V5 { field_5: SimpleEnum::V { field: 5}}, &SomeEnum::V5 { field_5: SimpleEnum::V { field: 3}}) is Ordering::Greater, 13);
assert!(compare(&SomeEnum::V5 { field_5: SimpleEnum::V { field: 3}}, &SomeEnum::V5 { field_5: SimpleEnum::V { field: 5}}) is Ordering::Less, 14);
}
}
Loading

0 comments on commit 3e9fb56

Please sign in to comment.