From 417a6d4482f939a494b2b66eadf36af506482399 Mon Sep 17 00:00:00 2001 From: nizam-supraoracles Date: Thu, 26 Dec 2024 11:44:41 +0530 Subject: [PATCH 1/7] enumerableMap `update_value` function is return old value --- .../framework/supra-stdlib/sources/enumerable_map.move | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/aptos-move/framework/supra-stdlib/sources/enumerable_map.move b/aptos-move/framework/supra-stdlib/sources/enumerable_map.move index dfc4c22d0895a..ed47b4aea0f3c 100644 --- a/aptos-move/framework/supra-stdlib/sources/enumerable_map.move +++ b/aptos-move/framework/supra-stdlib/sources/enumerable_map.move @@ -69,15 +69,16 @@ module supra_std::enumerable_map { return updated_keys } - /// Update the value of a key thats already present in the Enumerable Map - public fun update_value( + /// Update the value of a key thats already present in the Enumerable Map and return old value + public fun update_value( map: &mut EnumerableMap, key: K, new_value: V - ): KeyValue { + ): V { assert!(contains(map, key), error::not_found(EKEY_ABSENT)); + let old_value = table::borrow(&mut map.map, key).value; table::borrow_mut(&mut map.map, key).value = new_value; - KeyValue { key, value: new_value } + old_value } /// Remove single Key from the Enumerable Map From acb8e2010a1877ee124eb0829721825833ae15cb Mon Sep 17 00:00:00 2001 From: nizam-supraoracles Date: Thu, 26 Dec 2024 11:45:27 +0530 Subject: [PATCH 2/7] enumerableMap include `for_each_value` and `for_each_value_ref` method --- .../supra-stdlib/sources/enumerable_map.move | 78 +++++++++++++++---- 1 file changed, 62 insertions(+), 16 deletions(-) diff --git a/aptos-move/framework/supra-stdlib/sources/enumerable_map.move b/aptos-move/framework/supra-stdlib/sources/enumerable_map.move index ed47b4aea0f3c..0a86f139a61f9 100644 --- a/aptos-move/framework/supra-stdlib/sources/enumerable_map.move +++ b/aptos-move/framework/supra-stdlib/sources/enumerable_map.move @@ -15,7 +15,7 @@ module supra_std::enumerable_map { const EVECTOR_EMPTY: u64 = 3; /// Enumerable Map to store the key value pairs - struct EnumerableMap has store { + struct EnumerableMap has store { /// List of all keys list: vector, /// Key mapped to a tuple containing the (position of key in list and value corresponding to the key) @@ -23,31 +23,31 @@ module supra_std::enumerable_map { } /// Tuple to store the position of key in list and value corresponding to the key - struct Tuple has store, copy, drop { + struct Tuple has store, copy, drop { position: u64, value: V, } /// Return type - struct KeyValue has store, copy, drop { + struct KeyValue has store, copy, drop { key: K, value: V, } /// To create an empty enum map - public fun new_map(): EnumerableMap { + public fun new_map(): EnumerableMap { return EnumerableMap { list: vector::empty(), map: table::new>() } } /// Add Single Key in the Enumerable Map - public fun add_value(map: &mut EnumerableMap, key: K, value: V) { + public fun add_value(map: &mut EnumerableMap, key: K, value: V) { assert!(!contains(map, key), error::already_exists(EKEY_ALREADY_ADDED)); table::add(&mut map.map, key, Tuple { position: vector::length(&map.list), value }); vector::push_back(&mut map.list, key); } /// Add Multiple Keys in the Enumerable Map - public fun add_value_bulk( + public fun add_value_bulk( map: &mut EnumerableMap, keys: vector, values: vector @@ -82,7 +82,7 @@ module supra_std::enumerable_map { } /// Remove single Key from the Enumerable Map - public fun remove_value(map: &mut EnumerableMap, key: K) { + public fun remove_value(map: &mut EnumerableMap, key: K) { assert!(contains(map, key), error::not_found(EKEY_ABSENT)); let map_last_index = vector::length(&map.list) - 1; @@ -96,7 +96,7 @@ module supra_std::enumerable_map { } /// Remove Multiple Keys from the Enumerable Map - public fun remove_value_bulk( + public fun remove_value_bulk( map: &mut EnumerableMap, keys: vector ): vector { @@ -123,44 +123,66 @@ module supra_std::enumerable_map { } /// Will clear the entire data from the Enumerable Map - public fun clear(map: &mut EnumerableMap) { + public fun clear(map: &mut EnumerableMap) { let list = get_map_list(map); remove_value_bulk(map, list); } /// Returns the value of a key that is present in Enumerable Map - public fun get_value(map: & EnumerableMap, key: K): V { + public fun get_value(map: & EnumerableMap, key: K): V { table::borrow(&map.map, key).value } /// Returns reference to the value of a key that is present in Enumerable Map - public fun get_value_ref(map: & EnumerableMap, key: K): &V { + public fun get_value_ref(map: & EnumerableMap, key: K): &V { &table::borrow(&map.map, key).value } /// Returns the value of a key that is present in Enumerable Map - public fun get_value_mut(map: &mut EnumerableMap, key: K): &mut V { + public fun get_value_mut(map: &mut EnumerableMap, key: K): &mut V { &mut table::borrow_mut(&mut map.map, key).value } /// Returns the list of keys that the Enumerable Map contains - public fun get_map_list(map: &EnumerableMap): vector { + public fun get_map_list(map: &EnumerableMap): vector { return map.list } /// Check whether Key is present into the Enumerable map or not - public fun contains(map: &EnumerableMap, key: K): bool { + public fun contains(map: &EnumerableMap, key: K): bool { table::contains(&map.map, key) } /// Return current length of the EnumerableSetRing - public fun length(set: &EnumerableMap): u64 { + public fun length(set: &EnumerableMap): u64 { return vector::length(&set.list) } + /// Apply the function to each element in the EnumerableMap. + public inline fun for_each_value(set: &EnumerableMap, f: |V|) { + let i = 0; + let len = length(set); + while (i < len) { + let key = *vector::borrow(&set.list, i); + f(table::borrow(&set.map, key).value); + i = i + 1 + } + } + + /// Apply the function to a reference of each element in the EnumerableMap. + public inline fun for_each_value_ref(set: &EnumerableMap, f: |&V|) { + let i = 0; + let len = length(set); + while (i < len) { + let key = *vector::borrow(&set.list, i); + f(&table::borrow(&set.map, key).value); + i = i + 1 + } + } + #[test_only] - struct EnumerableMapTest has key { + struct EnumerableMapTest has key { e: EnumerableMap } @@ -280,4 +302,28 @@ module supra_std::enumerable_map { move_to(owner, EnumerableMapTest { e: enum_map }) } + + #[test(owner= @0x1111)] + public fun test_for_each_value_and_ref(owner: &signer) { + let enum_map = new_map(); + add_value(&mut enum_map, 1, 1); + add_value(&mut enum_map, 2, 2); + add_value(&mut enum_map, 3, 3); + add_value(&mut enum_map, 4, 4); + add_value(&mut enum_map, 5, 5); + add_value(&mut enum_map, 6, 6); + + let i = 1; + for_each_value(&enum_map, |v| { + assert!(i == v, 100); + i = i + 1; + }); + + let j = 1; + for_each_value_ref(&enum_map, |v| { + assert!(&j == v, 200); + j = j + 1; + }); + move_to(owner, EnumerableMapTest { e: enum_map }) + } } From 237eb2b74e76f12e6033579d3480c4acfc777425 Mon Sep 17 00:00:00 2001 From: nizam-supraoracles Date: Thu, 26 Dec 2024 12:28:26 +0530 Subject: [PATCH 3/7] enumerableMap - create 'filter' method --- .../supra-stdlib/sources/enumerable_map.move | 84 ++++++++----------- 1 file changed, 34 insertions(+), 50 deletions(-) diff --git a/aptos-move/framework/supra-stdlib/sources/enumerable_map.move b/aptos-move/framework/supra-stdlib/sources/enumerable_map.move index 0a86f139a61f9..f65e194ac8f3c 100644 --- a/aptos-move/framework/supra-stdlib/sources/enumerable_map.move +++ b/aptos-move/framework/supra-stdlib/sources/enumerable_map.move @@ -181,21 +181,35 @@ module supra_std::enumerable_map { } } + /// Filter the enumerableMap using the boolean function, removing all elements for which `p(e)` is not true. + public inline fun filter(set: &EnumerableMap, p: |&V|bool): vector { + let result = vector[]; + for_each_value(set, |v| { + if (p(&v)) vector::push_back(&mut result, v); + }); + result + } + #[test_only] struct EnumerableMapTest has key { e: EnumerableMap } - #[test(owner= @0x1111)] - public fun test_add_value(owner: &signer) { + #[test_only] + fun get_enum_map(): EnumerableMap { let enum_map = new_map(); - add_value(&mut enum_map, 1, 1); add_value(&mut enum_map, 2, 2); add_value(&mut enum_map, 3, 3); add_value(&mut enum_map, 4, 4); add_value(&mut enum_map, 5, 5); add_value(&mut enum_map, 6, 6); + enum_map + } + + #[test(owner= @0x1111)] + public fun test_add_value(owner: &signer) { + let enum_map = get_enum_map(); assert!(contains(&enum_map, 3), 1); assert!(length(&enum_map) == 6, 2); @@ -205,14 +219,7 @@ module supra_std::enumerable_map { #[test(owner= @0x1111)] public fun test_add_value_bulk(owner: &signer) { - let enum_map = new_map(); - - add_value(&mut enum_map, 1, 1); - add_value(&mut enum_map, 2, 2); - add_value(&mut enum_map, 3, 3); - add_value(&mut enum_map, 4, 4); - add_value(&mut enum_map, 5, 5); - add_value(&mut enum_map, 6, 6); + let enum_map = get_enum_map(); add_value_bulk(&mut enum_map, vector[7, 8, 9], vector[7, 8, 9]); @@ -225,14 +232,7 @@ module supra_std::enumerable_map { #[test(owner= @0x1111)] #[expected_failure(abort_code = 1, location = Self)] public fun test_remove_value(owner: &signer) { - let enum_map = new_map(); - - add_value(&mut enum_map, 1, 1); - add_value(&mut enum_map, 2, 2); - add_value(&mut enum_map, 3, 3); - add_value(&mut enum_map, 4, 4); - add_value(&mut enum_map, 5, 5); - add_value(&mut enum_map, 6, 6); + let enum_map = get_enum_map(); remove_value(&mut enum_map, 1); remove_value(&mut enum_map, 2); @@ -247,14 +247,7 @@ module supra_std::enumerable_map { #[test(owner= @0x1111)] #[expected_failure(abort_code = 2, location = Self)] public fun test_remove_bulk_value(owner: &signer) { - let enum_map = new_map(); - - add_value(&mut enum_map, 1, 1); - add_value(&mut enum_map, 2, 2); - add_value(&mut enum_map, 3, 3); - add_value(&mut enum_map, 4, 4); - add_value(&mut enum_map, 5, 5); - add_value(&mut enum_map, 6, 6); + let enum_map = get_enum_map(); remove_value_bulk(&mut enum_map, vector[1, 2, 3]); @@ -267,14 +260,7 @@ module supra_std::enumerable_map { #[test(owner= @0x1111)] #[expected_failure(abort_code = 3, location = Self)] public fun test_update_value(owner: &signer) { - let enum_map = new_map(); - - add_value(&mut enum_map, 1, 1); - add_value(&mut enum_map, 2, 2); - add_value(&mut enum_map, 3, 3); - add_value(&mut enum_map, 4, 4); - add_value(&mut enum_map, 5, 5); - add_value(&mut enum_map, 6, 6); + let enum_map = get_enum_map(); update_value(&mut enum_map, 1, 7); @@ -287,14 +273,7 @@ module supra_std::enumerable_map { #[test(owner= @0x1111)] public fun test_clear(owner: &signer) { - let enum_map = new_map(); - - add_value(&mut enum_map, 1, 1); - add_value(&mut enum_map, 2, 2); - add_value(&mut enum_map, 3, 3); - add_value(&mut enum_map, 4, 4); - add_value(&mut enum_map, 5, 5); - add_value(&mut enum_map, 6, 6); + let enum_map = get_enum_map(); clear(&mut enum_map); @@ -305,13 +284,7 @@ module supra_std::enumerable_map { #[test(owner= @0x1111)] public fun test_for_each_value_and_ref(owner: &signer) { - let enum_map = new_map(); - add_value(&mut enum_map, 1, 1); - add_value(&mut enum_map, 2, 2); - add_value(&mut enum_map, 3, 3); - add_value(&mut enum_map, 4, 4); - add_value(&mut enum_map, 5, 5); - add_value(&mut enum_map, 6, 6); + let enum_map = get_enum_map(); let i = 1; for_each_value(&enum_map, |v| { @@ -326,4 +299,15 @@ module supra_std::enumerable_map { }); move_to(owner, EnumerableMapTest { e: enum_map }) } + + #[test(owner= @0x1111)] + public fun test_filter(owner: &signer) { + let enum_map = get_enum_map(); + + let result = filter(&enum_map, |v| *v > 3); + + assert!(result == vector[4, 5, 6], 300); + + move_to(owner, EnumerableMapTest { e: enum_map }) + } } From 5d71a9a44c5d6462a5e4ed308209eefc245478e0 Mon Sep 17 00:00:00 2001 From: nizam-supraoracles Date: Thu, 26 Dec 2024 20:33:48 +0530 Subject: [PATCH 4/7] enumerableMap PR comments address --- .../supra-stdlib/doc/enumerable_map.md | 129 +++++++++++++++--- .../supra-stdlib/sources/enumerable_map.move | 45 ++++-- 2 files changed, 149 insertions(+), 25 deletions(-) diff --git a/aptos-move/framework/supra-stdlib/doc/enumerable_map.md b/aptos-move/framework/supra-stdlib/doc/enumerable_map.md index dedf74812516f..f168461adc6a4 100644 --- a/aptos-move/framework/supra-stdlib/doc/enumerable_map.md +++ b/aptos-move/framework/supra-stdlib/doc/enumerable_map.md @@ -26,6 +26,9 @@ The module includes error handling and a suite of test functions for validation. - [Function `get_map_list`](#0x1_enumerable_map_get_map_list) - [Function `contains`](#0x1_enumerable_map_contains) - [Function `length`](#0x1_enumerable_map_length) +- [Function `for_each_value`](#0x1_enumerable_map_for_each_value) +- [Function `for_each_value_ref`](#0x1_enumerable_map_for_each_value_ref) +- [Function `filter`](#0x1_enumerable_map_filter)
use 0x1::error;
@@ -188,7 +191,7 @@ To create an empty enum map
 Implementation
 
 
-
public fun new_map<K : copy + drop, V : store+drop+copy>(): EnumerableMap<K, V> {
+
public fun new_map<K: copy + drop, V: store+drop+copy>(): EnumerableMap<K, V> {
     return EnumerableMap<K, V> { list: vector::empty<K>(), map: table::new<K, Tuple<V>>() }
 }
 
@@ -213,7 +216,7 @@ Add Single Key in the Enumerable Map Implementation -
public fun add_value<K : copy+drop, V : store+drop+copy>(map: &mut EnumerableMap<K, V>, key: K, value: V) {
+
public fun add_value<K: copy+drop, V: store+drop+copy>(map: &mut EnumerableMap<K, V>, key: K, value: V) {
     assert!(!contains(map, key), error::already_exists(EKEY_ALREADY_ADDED));
     table::add(&mut map.map, key, Tuple<V> { position: vector::length(&map.list), value });
     vector::push_back(&mut map.list, key);
@@ -240,7 +243,7 @@ Add Multiple Keys in the Enumerable Map
 Implementation
 
 
-
public fun add_value_bulk<K: copy+drop, V : store+drop+copy>(
+
public fun add_value_bulk<K: copy+drop, V: store+drop+copy>(
     map: &mut EnumerableMap<K, V>,
     keys: vector<K>,
     values: vector<V>
@@ -271,10 +274,10 @@ Add Multiple Keys in the Enumerable Map
 
 ## Function `update_value`
 
-Update the value of a key thats already present in the Enumerable Map
+Update the value of a key thats already present in the Enumerable Map and return old value
 
 
-
public fun update_value<K: copy, drop, V: copy, drop, store>(map: &mut enumerable_map::EnumerableMap<K, V>, key: K, new_value: V): enumerable_map::KeyValue<K, V>
+
public fun update_value<K: copy, drop, V: copy, drop, store>(map: &mut enumerable_map::EnumerableMap<K, V>, key: K, new_value: V): V
 
@@ -283,14 +286,15 @@ Update the value of a key thats already present in the Enumerable Map Implementation -
public fun update_value<K: copy+drop, V : store+drop+copy>(
+
public fun update_value<K: copy+drop, V: store+drop+copy>(
     map: &mut EnumerableMap<K, V>,
     key: K,
     new_value: V
-): KeyValue<K, V> {
+): V {
     assert!(contains(map, key), error::not_found(EKEY_ABSENT));
+    let old_value = table::borrow(&mut map.map, key).value;
     table::borrow_mut(&mut map.map, key).value = new_value;
-    KeyValue { key, value: new_value }
+    old_value
 }
 
@@ -314,7 +318,7 @@ Remove single Key from the Enumerable Map Implementation -
public fun remove_value<K : copy+drop, V : store+drop+copy>(map: &mut EnumerableMap<K, V>, key: K) {
+
public fun remove_value<K: copy+drop, V: store+drop+copy>(map: &mut EnumerableMap<K, V>, key: K) {
     assert!(contains(map, key), error::not_found(EKEY_ABSENT));
 
     let map_last_index = vector::length(&map.list) - 1;
@@ -348,7 +352,7 @@ Remove Multiple Keys from the Enumerable Map
 Implementation
 
 
-
public fun remove_value_bulk<K : copy+drop, V : store+drop+copy>(
+
public fun remove_value_bulk<K: copy+drop, V: store+drop+copy>(
     map: &mut EnumerableMap<K, V>,
     keys: vector<K>
 ): vector<K> {
@@ -395,7 +399,7 @@ Will clear the entire data from the Enumerable Map
 Implementation
 
 
-
public fun clear<K : copy+drop, V : store+drop+copy>(map: &mut EnumerableMap<K, V>) {
+
public fun clear<K: copy+drop, V: store+drop+copy>(map: &mut EnumerableMap<K, V>) {
     let list = get_map_list(map);
     remove_value_bulk(map, list);
 }
@@ -421,7 +425,7 @@ Returns the value of a key that is present in Enumerable Map
 Implementation
 
 
-
public fun get_value<K : copy+drop, V : store+drop+copy>(map: & EnumerableMap<K, V>, key: K): V {
+
public fun get_value<K: copy+drop, V: store+drop+copy>(map: & EnumerableMap<K, V>, key: K): V {
     table::borrow(&map.map, key).value
 }
 
@@ -446,7 +450,7 @@ Returns reference to the value of a key that is present in Enumerable Map Implementation -
public fun get_value_ref<K : copy+drop, V : store+drop+copy>(map: & EnumerableMap<K, V>, key: K): &V {
+
public fun get_value_ref<K: copy+drop, V: store+drop+copy>(map: & EnumerableMap<K, V>, key: K): &V {
     &table::borrow(&map.map, key).value
 }
 
@@ -471,7 +475,7 @@ Returns the value of a key that is present in Enumerable Map Implementation -
public fun get_value_mut<K : copy+drop, V : store+drop+copy>(map: &mut EnumerableMap<K, V>, key: K): &mut V {
+
public fun get_value_mut<K: copy+drop, V: store+drop+copy>(map: &mut EnumerableMap<K, V>, key: K): &mut V {
     &mut table::borrow_mut(&mut map.map, key).value
 }
 
@@ -496,7 +500,7 @@ Returns the list of keys that the Enumerable Map contains Implementation -
public fun get_map_list<K : copy+drop, V : store+drop+copy>(map: &EnumerableMap<K, V>): vector<K> {
+
public fun get_map_list<K: copy+drop, V: store+drop+copy>(map: &EnumerableMap<K, V>): vector<K> {
     return map.list
 }
 
@@ -521,7 +525,7 @@ Check whether Key is present into the Enumerable map or not Implementation -
public fun contains<K: copy+drop, V : store+drop+copy>(map: &EnumerableMap<K, V>, key: K): bool {
+
public fun contains<K: copy+drop, V: store+drop+copy>(map: &EnumerableMap<K, V>, key: K): bool {
     table::contains(&map.map, key)
 }
 
@@ -546,13 +550,104 @@ Return current length of the EnumerableSetRing Implementation -
public fun length<K : copy+drop, V : store+drop+copy>(set: &EnumerableMap<K, V>): u64 {
+
public fun length<K: copy+drop, V: store+drop+copy>(set: &EnumerableMap<K, V>): u64 {
     return vector::length(&set.list)
 }
 
+ + + + +## Function `for_each_value` + +Apply the function to each element in the EnumerableMap. + + +
public fun for_each_value<K: copy, drop, V: copy, drop, store>(set: &enumerable_map::EnumerableMap<K, V>, f: |V|)
+
+ + + +
+Implementation + + +
public inline fun for_each_value<K: copy+drop, V: store+drop+copy>(set: &EnumerableMap<K, V>, f: |V|) {
+    let i = 0;
+    let len = length(set);
+    while (i < len) {
+        let key = *vector::borrow(&set.list, i);
+        f(table::borrow(&set.map, key).value);
+        i = i + 1
+    }
+}
+
+ + + +
+ + + +## Function `for_each_value_ref` + +Apply the function to a reference of each element in the EnumerableMap. + + +
public fun for_each_value_ref<K: copy, drop, V: copy, drop, store>(set: &enumerable_map::EnumerableMap<K, V>, f: |&V|)
+
+ + + +
+Implementation + + +
public inline fun for_each_value_ref<K: copy+drop, V: store+drop+copy>(set: &EnumerableMap<K, V>, f: |&V|) {
+    let i = 0;
+    let len = length(set);
+    while (i < len) {
+        let key = *vector::borrow(&set.list, i);
+        f(&table::borrow(&set.map, key).value);
+        i = i + 1
+    }
+}
+
+ + + +
+ + + +## Function `filter` + +Filter the enumerableMap using the boolean function, removing all elements for which p(e) is not true. + + +
public fun filter<K: copy, drop, V: copy, drop, store>(set: &enumerable_map::EnumerableMap<K, V>, p: |&V|bool): vector<V>
+
+ + + +
+Implementation + + +
public inline fun filter<K: copy+drop, V: store+drop+copy>(set: &EnumerableMap<K, V>, p: |&V|bool): vector<V> {
+    let result = vector<V>[];
+    for_each_value(set, |v| {
+        if (p(&v)) vector::push_back(&mut result, v);
+    });
+    result
+}
+
+ + +
diff --git a/aptos-move/framework/supra-stdlib/sources/enumerable_map.move b/aptos-move/framework/supra-stdlib/sources/enumerable_map.move index f65e194ac8f3c..b5303931326c4 100644 --- a/aptos-move/framework/supra-stdlib/sources/enumerable_map.move +++ b/aptos-move/framework/supra-stdlib/sources/enumerable_map.move @@ -82,7 +82,7 @@ module supra_std::enumerable_map { } /// Remove single Key from the Enumerable Map - public fun remove_value(map: &mut EnumerableMap, key: K) { + public fun remove_value(map: &mut EnumerableMap, key: K): V { assert!(contains(map, key), error::not_found(EKEY_ABSENT)); let map_last_index = vector::length(&map.list) - 1; @@ -92,7 +92,7 @@ module supra_std::enumerable_map { vector::swap(&mut map.list, index_of_element, map_last_index); tuple_to_modify.position = index_of_element; vector::pop_back(&mut map.list); - table::remove(&mut map.map, key); + table::remove(&mut map.map, key).value } /// Remove Multiple Keys from the Enumerable Map @@ -181,11 +181,33 @@ module supra_std::enumerable_map { } } + /// Apply the function to a mutable reference in the EnumerableMap. + public inline fun for_each_value_mut(set: &mut EnumerableMap, f: |&mut V|) { + let i = 0; + let len = length(set); + while (i < len) { + let key = *vector::borrow(&set.list, i); + f(&mut table::borrow_mut(&mut set.map, key).value); + i = i + 1 + } + } + + /// Iterates over each key-value pair in an EnumerableMap and applies the provided function + public inline fun for_each_keyval(set: &EnumerableMap, f: |K, V|) { + let i = 0; + let len = length(set); + while (i < len) { + let key = *vector::borrow(&set.list, i); + f(key, table::borrow(&set.map, key).value); + i = i + 1 + } + } + /// Filter the enumerableMap using the boolean function, removing all elements for which `p(e)` is not true. public inline fun filter(set: &EnumerableMap, p: |&V|bool): vector { let result = vector[]; - for_each_value(set, |v| { - if (p(&v)) vector::push_back(&mut result, v); + for_each_value_ref(set, |v| { + if (p(v)) vector::push_back(&mut result, *v); }); result } @@ -287,16 +309,23 @@ module supra_std::enumerable_map { let enum_map = get_enum_map(); let i = 1; - for_each_value(&enum_map, |v| { - assert!(i == v, 100); + for_each_value_ref(&enum_map, |v| { + assert!(v == &i, 100); i = i + 1; }); let j = 1; - for_each_value_ref(&enum_map, |v| { - assert!(&j == v, 200); + for_each_value_mut(&mut enum_map, |v| { + *v = j + 1; // update value with 1 increament j = j + 1; }); + + let k = 1; + for_each_value(&enum_map, |v| { + assert!(v == k + 1, 300); + k = k + 1; + }); + move_to(owner, EnumerableMapTest { e: enum_map }) } From 50ca43dbff97423b64d56ae71b8bb9b938050041 Mon Sep 17 00:00:00 2001 From: nizam-supraoracles Date: Fri, 27 Dec 2024 15:18:24 +0530 Subject: [PATCH 5/7] enumerable_map - implement `map` `map_ref` and `filter_map` methods and there unit tests --- .../supra-stdlib/sources/enumerable_map.move | 60 ++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/aptos-move/framework/supra-stdlib/sources/enumerable_map.move b/aptos-move/framework/supra-stdlib/sources/enumerable_map.move index b5303931326c4..2a0c67256a287 100644 --- a/aptos-move/framework/supra-stdlib/sources/enumerable_map.move +++ b/aptos-move/framework/supra-stdlib/sources/enumerable_map.move @@ -203,7 +203,7 @@ module supra_std::enumerable_map { } } - /// Filter the enumerableMap using the boolean function, removing all elements for which `p(e)` is not true. + /// Filter the enumerableMap using the boolean function, removing all elements for which `p(v)` is not true. public inline fun filter(set: &EnumerableMap, p: |&V|bool): vector { let result = vector[]; for_each_value_ref(set, |v| { @@ -212,6 +212,35 @@ module supra_std::enumerable_map { result } + /// Transforms values in an EnumerableMap using the provided function and returns a vector of results. + public inline fun map(set: &EnumerableMap, f: |V|T): vector { + let result = vector[]; + for_each_value(set, |elem| vector::push_back(&mut result, f(elem))); + result + } + + /// Transforms values in an EnumerableMap by reference using the provided function and returns a vector of results. + public inline fun map_ref(set: &EnumerableMap, f: |&V|T): vector { + let result = vector[]; + for_each_value_ref(set, |elem| vector::push_back(&mut result, f(elem))); + result + } + + /// Applies a filter and transformation function to values in an EnumerableMap, returning a vector of results. + public inline fun filter_map( + set: &EnumerableMap, + f: |V| (bool, T) + ): vector { + let result = vector[]; + for_each_value(set, |v| { + let (should_include, transformed_value) = f(v); + if (should_include) { + vector::push_back(&mut result, transformed_value); + } + }); + result + } + #[test_only] struct EnumerableMapTest has key { e: EnumerableMap @@ -339,4 +368,33 @@ module supra_std::enumerable_map { move_to(owner, EnumerableMapTest { e: enum_map }) } + + #[test(owner= @0x1111)] + public fun test_map_and_ref(owner: &signer) { + let enum_map = get_enum_map(); + + let result = map(&enum_map, |v| v * 3); + + assert!(result == vector[3, 6, 9, 12, 15, 18], 400); + + let result = map_ref(&enum_map, |v| *v * 2); + + assert!(result == vector[2, 4, 6, 8, 10, 12], 500); + + move_to(owner, EnumerableMapTest { e: enum_map }) + } + + #[test(owner= @0x1111)] + public fun test_filter_map_and_ref(owner: &signer) { + let enum_map = get_enum_map(); + + let result = filter_map(&enum_map, |v| + if (v % 2 == 0) (true, v) + else (false, 0) + ); + + assert!(result == vector[2, 4, 6], 600); + + move_to(owner, EnumerableMapTest { e: enum_map }) + } } From 3aa0d1cc09dcf6fe9102d2b7fed0f647f4247070 Mon Sep 17 00:00:00 2001 From: nizam-supraoracles Date: Fri, 27 Dec 2024 17:13:52 +0530 Subject: [PATCH 6/7] enumerable_map - access properties via function instead of direct access to properties --- .../supra-stdlib/doc/enumerable_map.md | 200 +++++++++++++++++- .../supra-stdlib/sources/enumerable_map.move | 20 +- 2 files changed, 203 insertions(+), 17 deletions(-) diff --git a/aptos-move/framework/supra-stdlib/doc/enumerable_map.md b/aptos-move/framework/supra-stdlib/doc/enumerable_map.md index f168461adc6a4..87b8d8e8cc037 100644 --- a/aptos-move/framework/supra-stdlib/doc/enumerable_map.md +++ b/aptos-move/framework/supra-stdlib/doc/enumerable_map.md @@ -22,13 +22,19 @@ The module includes error handling and a suite of test functions for validation. - [Function `clear`](#0x1_enumerable_map_clear) - [Function `get_value`](#0x1_enumerable_map_get_value) - [Function `get_value_ref`](#0x1_enumerable_map_get_value_ref) +- [Function `get_key_by_index`](#0x1_enumerable_map_get_key_by_index) - [Function `get_value_mut`](#0x1_enumerable_map_get_value_mut) - [Function `get_map_list`](#0x1_enumerable_map_get_map_list) - [Function `contains`](#0x1_enumerable_map_contains) - [Function `length`](#0x1_enumerable_map_length) - [Function `for_each_value`](#0x1_enumerable_map_for_each_value) - [Function `for_each_value_ref`](#0x1_enumerable_map_for_each_value_ref) +- [Function `for_each_value_mut`](#0x1_enumerable_map_for_each_value_mut) +- [Function `for_each_keyval`](#0x1_enumerable_map_for_each_keyval) - [Function `filter`](#0x1_enumerable_map_filter) +- [Function `map`](#0x1_enumerable_map_map) +- [Function `map_ref`](#0x1_enumerable_map_map_ref) +- [Function `filter_map`](#0x1_enumerable_map_filter_map)
use 0x1::error;
@@ -309,7 +315,7 @@ Update the value of a key thats already present in the Enumerable Map and return
 Remove single Key from the Enumerable Map
 
 
-
public fun remove_value<K: copy, drop, V: copy, drop, store>(map: &mut enumerable_map::EnumerableMap<K, V>, key: K)
+
public fun remove_value<K: copy, drop, V: copy, drop, store>(map: &mut enumerable_map::EnumerableMap<K, V>, key: K): V
 
@@ -318,7 +324,7 @@ Remove single Key from the Enumerable Map Implementation -
public fun remove_value<K: copy+drop, V: store+drop+copy>(map: &mut EnumerableMap<K, V>, key: K) {
+
public fun remove_value<K: copy+drop, V: store+drop+copy>(map: &mut EnumerableMap<K, V>, key: K): V {
     assert!(contains(map, key), error::not_found(EKEY_ABSENT));
 
     let map_last_index = vector::length(&map.list) - 1;
@@ -328,7 +334,7 @@ Remove single Key from the Enumerable Map
     vector::swap(&mut map.list, index_of_element, map_last_index);
     tuple_to_modify.position = index_of_element;
     vector::pop_back(&mut map.list);
-    table::remove(&mut map.map, key);
+    table::remove(&mut map.map, key).value
 }
 
@@ -457,6 +463,31 @@ Returns reference to the value of a key that is present in Enumerable Map + + + + +## Function `get_key_by_index` + +Retrieves the key at the specified index from the EnumerableMap's key list. + + +
public fun get_key_by_index<K: copy, drop, V: copy, drop, store>(set: &enumerable_map::EnumerableMap<K, V>, index: u64): K
+
+ + + +
+Implementation + + +
public fun get_key_by_index<K: copy+drop, V: store+drop+copy>(set: &EnumerableMap<K, V>, index: u64): K {
+    *vector::borrow(&set.list, index)
+}
+
+ + +
@@ -579,8 +610,8 @@ Apply the function to each element in the EnumerableMap. let i = 0; let len = length(set); while (i < len) { - let key = *vector::borrow(&set.list, i); - f(table::borrow(&set.map, key).value); + let key = get_key_by_index(set, i); + f(*get_value_ref(set, key)); i = i + 1 } } @@ -610,8 +641,70 @@ Apply the function to a reference of each element in the EnumerableMap. let i = 0; let len = length(set); while (i < len) { - let key = *vector::borrow(&set.list, i); - f(&table::borrow(&set.map, key).value); + let key = get_key_by_index(set, i); + f(get_value_ref(set, key)); + i = i + 1 + } +} +
+ + + + + + + +## Function `for_each_value_mut` + +Apply the function to a mutable reference in the EnumerableMap. + + +
public fun for_each_value_mut<K: copy, drop, V: copy, drop, store>(set: &mut enumerable_map::EnumerableMap<K, V>, f: |&mut V|)
+
+ + + +
+Implementation + + +
public inline fun for_each_value_mut<K: copy+drop, V: store+drop+copy>(set: &mut EnumerableMap<K, V>, f: |&mut V|) {
+    let i = 0;
+    let len = length(set);
+    while (i < len) {
+        let key = get_key_by_index(set, i);
+        f(get_value_mut(set, key));
+        i = i + 1
+    }
+}
+
+ + + +
+ + + +## Function `for_each_keyval` + +Iterates over each key-value pair in an EnumerableMap and applies the provided function + + +
public fun for_each_keyval<K: copy, drop, V: copy, drop, store>(set: &enumerable_map::EnumerableMap<K, V>, f: |(K, V)|)
+
+ + + +
+Implementation + + +
public inline fun for_each_keyval<K: copy+drop, V: store+drop+copy>(set: &EnumerableMap<K, V>, f: |K, V|) {
+    let i = 0;
+    let len = length(set);
+    while (i < len) {
+        let key = get_key_by_index(set, i);
+        f(key, *get_value_ref(set, key));
         i = i + 1
     }
 }
@@ -625,7 +718,7 @@ Apply the function to a reference of each element in the EnumerableMap.
 
 ## Function `filter`
 
-Filter the enumerableMap using the boolean function, removing all elements for which p(e) is not true.
+Filter the enumerableMap using the boolean function, removing all elements for which p(v) is not true.
 
 
 
public fun filter<K: copy, drop, V: copy, drop, store>(set: &enumerable_map::EnumerableMap<K, V>, p: |&V|bool): vector<V>
@@ -639,8 +732,97 @@ Filter the enumerableMap using the boolean function, removing all elements for w
 
 
public inline fun filter<K: copy+drop, V: store+drop+copy>(set: &EnumerableMap<K, V>, p: |&V|bool): vector<V> {
     let result = vector<V>[];
+    for_each_value_ref(set, |v| {
+        if (p(v)) vector::push_back(&mut result, *v);
+    });
+    result
+}
+
+ + + +
+ + + +## Function `map` + +Transforms values in an EnumerableMap using the provided function and returns a vector of results. + + +
public fun map<K: copy, drop, V: copy, drop, store, T>(set: &enumerable_map::EnumerableMap<K, V>, f: |V|T): vector<T>
+
+ + + +
+Implementation + + +
public inline fun map<K: copy+drop, V: store+drop+copy, T>(set: &EnumerableMap<K, V>, f: |V|T): vector<T> {
+    let result = vector<T>[];
+    for_each_value(set, |elem| vector::push_back(&mut result, f(elem)));
+    result
+}
+
+ + + +
+ + + +## Function `map_ref` + +Transforms values in an EnumerableMap by reference using the provided function and returns a vector of results. + + +
public fun map_ref<K: copy, drop, V: copy, drop, store, T>(set: &enumerable_map::EnumerableMap<K, V>, f: |&V|T): vector<T>
+
+ + + +
+Implementation + + +
public inline fun map_ref<K: copy+drop, V: store+drop+copy, T>(set: &EnumerableMap<K, V>, f: |&V|T): vector<T> {
+    let result = vector<T>[];
+    for_each_value_ref(set, |elem| vector::push_back(&mut result, f(elem)));
+    result
+}
+
+ + + +
+ + + +## Function `filter_map` + +Applies a filter and transformation function to values in an EnumerableMap, returning a vector of results. + + +
public fun filter_map<K: copy, drop, V: copy, drop, store, T>(set: &enumerable_map::EnumerableMap<K, V>, f: |V|(bool, T)): vector<T>
+
+ + + +
+Implementation + + +
public inline fun filter_map<K: copy+drop, V: store+drop+copy, T>(
+    set: &EnumerableMap<K, V>,
+    f: |V| (bool, T)
+): vector<T> {
+    let result = vector<T>[];
     for_each_value(set, |v| {
-        if (p(&v)) vector::push_back(&mut result, v);
+        let (should_include, transformed_value) = f(v);
+        if (should_include) {
+            vector::push_back(&mut result, transformed_value);
+        }
     });
     result
 }
diff --git a/aptos-move/framework/supra-stdlib/sources/enumerable_map.move b/aptos-move/framework/supra-stdlib/sources/enumerable_map.move
index 2a0c67256a287..df2b6a67b2e4f 100644
--- a/aptos-move/framework/supra-stdlib/sources/enumerable_map.move
+++ b/aptos-move/framework/supra-stdlib/sources/enumerable_map.move
@@ -138,6 +138,10 @@ module supra_std::enumerable_map {
         &table::borrow(&map.map, key).value
     }
 
+    /// Retrieves the key at the specified index from the EnumerableMap's key list.
+    public fun get_key_by_index(set: &EnumerableMap, index: u64): K {
+        *vector::borrow(&set.list, index)
+    }
 
     /// Returns the value of a key that is present in Enumerable Map
     public fun get_value_mut(map: &mut EnumerableMap, key: K): &mut V {
@@ -164,8 +168,8 @@ module supra_std::enumerable_map {
         let i = 0;
         let len = length(set);
         while (i < len) {
-            let key = *vector::borrow(&set.list, i);
-            f(table::borrow(&set.map, key).value);
+            let key = get_key_by_index(set, i);
+            f(*get_value_ref(set, key));
             i = i + 1
         }
     }
@@ -175,8 +179,8 @@ module supra_std::enumerable_map {
         let i = 0;
         let len = length(set);
         while (i < len) {
-            let key = *vector::borrow(&set.list, i);
-            f(&table::borrow(&set.map, key).value);
+            let key = get_key_by_index(set, i);
+            f(get_value_ref(set, key));
             i = i + 1
         }
     }
@@ -186,8 +190,8 @@ module supra_std::enumerable_map {
         let i = 0;
         let len = length(set);
         while (i < len) {
-            let key = *vector::borrow(&set.list, i);
-            f(&mut table::borrow_mut(&mut set.map, key).value);
+            let key = get_key_by_index(set, i);
+            f(get_value_mut(set, key));
             i = i + 1
         }
     }
@@ -197,8 +201,8 @@ module supra_std::enumerable_map {
         let i = 0;
         let len = length(set);
         while (i < len) {
-            let key = *vector::borrow(&set.list, i);
-            f(key, table::borrow(&set.map, key).value);
+            let key = get_key_by_index(set, i);
+            f(key, *get_value_ref(set, key));
             i = i + 1
         }
     }

From 1a061e29b887a7e93aa002eac64c8d64edb878d3 Mon Sep 17 00:00:00 2001
From: nizam-supraoracles 
Date: Fri, 27 Dec 2024 17:15:04 +0530
Subject: [PATCH 7/7] automation registry - `get_active_task_ids` function is
 now usitlise enumerable_map's `filter_map` method

---
 .../doc/automation_registry_state.md          | 27 +++++-------
 .../sources/automation_registry_state.move    | 41 +++++++++----------
 2 files changed, 30 insertions(+), 38 deletions(-)

diff --git a/aptos-move/framework/supra-framework/doc/automation_registry_state.md b/aptos-move/framework/supra-framework/doc/automation_registry_state.md
index c2ac0ed343077..e5556baaa7fba 100644
--- a/aptos-move/framework/supra-framework/doc/automation_registry_state.md
+++ b/aptos-move/framework/supra-framework/doc/automation_registry_state.md
@@ -461,7 +461,7 @@ The lenght of the transaction hash.
 
         // Tasks that are active during next epoch and are not cancled
         // current_time shows the start time of the current new epoch.
-        if (task.state != CANCELLED && task.expiry_time > (current_time + epoch_interval_secs) ) {
+        if (task.state != CANCELLED && task.expiry_time > (current_time + epoch_interval_secs)) {
             gas_committed_for_next_epoch = gas_committed_for_next_epoch + task.max_gas_amount;
         };
 
@@ -564,7 +564,7 @@ Committed gas-limit is updated by reducing it with the max-gas-amount of the can
 Implementation
 
 
-
public (friend) fun cancel_task(owner: &signer, id: u64): AutomationTaskMetaData acquires AutomationRegistryState {
+
public(friend) fun cancel_task(owner: &signer, id: u64): AutomationTaskMetaData acquires AutomationRegistryState {
     let state = borrow_global_mut<AutomationRegistryState>(@supra_framework);
     assert!(enumerable_map::contains(&state.tasks, id), EAUTOMATION_TASK_NOT_FOUND);
 
@@ -607,7 +607,7 @@ If the committed gas amount for the next epoch is greater then the new gas limit
 Implementation
 
 
-
public (friend) fun update_automation_gas_limit(
+
public(friend) fun update_automation_gas_limit(
     supra_framework: &signer,
     automation_gas_limit: u64
 ) acquires AutomationRegistryState {
@@ -647,16 +647,11 @@ as cancellation takes effect in the next epoch only.
 
public(friend) fun get_active_task_ids(): vector<u64> acquires AutomationRegistryState {
     let state = borrow_global<AutomationRegistryState>(@supra_framework);
 
-    let active_task_ids = vector[];
-    let ids = enumerable_map::get_map_list(&state.tasks);
-
-    vector::for_each(ids, |id| {
-        let task = enumerable_map::get_value_ref(&state.tasks, id);
-        if (task.state != PENDING) {
-            vector::push_back(&mut active_task_ids, id);
-        };
-    });
-    return active_task_ids
+    enumerable_map::filter_map(&state.tasks, |task| {
+        let task: AutomationTaskMetaData = task; // we need to define task type here to avoid compiler error
+        if (task.state != PENDING) (true, task.id)
+        else (false, task.id)
+    })
 }
 
@@ -681,7 +676,7 @@ Error will be returned if entry with specified ID does not exist. Implementation -
public (friend) fun get_task_details(id: u64): AutomationTaskMetaData acquires AutomationRegistryState {
+
public(friend) fun get_task_details(id: u64): AutomationTaskMetaData acquires AutomationRegistryState {
     let automation_task_metadata = borrow_global<AutomationRegistryState>(@supra_framework);
     assert!(enumerable_map::contains(&automation_task_metadata.tasks, id), EAUTOMATION_TASK_NOT_FOUND);
     enumerable_map::get_value(&automation_task_metadata.tasks, id)
@@ -713,7 +708,7 @@ Checks whether there is an active task in registry with specified input task id.
     if (enumerable_map::contains(&automation_task_metadata.tasks, id)) {
         let value = enumerable_map::get_value_ref(&automation_task_metadata.tasks, id);
         value.state != PENDING
-    } else  {
+    } else {
         false
     }
 }
@@ -739,7 +734,7 @@ Returns next task index in registry
 Implementation
 
 
-
public (friend) fun get_next_task_index(): u64 acquires AutomationRegistryState {
+
public(friend) fun get_next_task_index(): u64 acquires AutomationRegistryState {
     let state = borrow_global<AutomationRegistryState>(@supra_framework);
     state.current_index
 }
diff --git a/aptos-move/framework/supra-framework/sources/automation_registry_state.move b/aptos-move/framework/supra-framework/sources/automation_registry_state.move
index 4e1f0d926fd2b..1a86c6bf38c21 100644
--- a/aptos-move/framework/supra-framework/sources/automation_registry_state.move
+++ b/aptos-move/framework/supra-framework/sources/automation_registry_state.move
@@ -5,12 +5,13 @@ module supra_framework::automation_registry_state {
 
     use std::signer;
     use std::vector;
-    use supra_framework::event;
 
     use supra_std::enumerable_map::{Self, EnumerableMap};
 
+    use supra_framework::event;
     use supra_framework::system_addresses;
     use supra_framework::timestamp;
+
     #[test_only]
     use supra_framework::account;
 
@@ -126,7 +127,7 @@ module supra_framework::automation_registry_state {
 
             // Tasks that are active during next epoch and are not cancled
             // current_time shows the start time of the current new epoch.
-            if (task.state != CANCELLED && task.expiry_time > (current_time + epoch_interval_secs) ) {
+            if (task.state != CANCELLED && task.expiry_time > (current_time + epoch_interval_secs)) {
                 gas_committed_for_next_epoch = gas_committed_for_next_epoch + task.max_gas_amount;
             };
 
@@ -189,7 +190,7 @@ module supra_framework::automation_registry_state {
     ///   - pending, it is removed form the list.
     ///   - cancelled, an error is reported
     /// Committed gas-limit is updated by reducing it with the max-gas-amount of the cancelled task.
-    public (friend) fun cancel_task(owner: &signer, id: u64): AutomationTaskMetaData acquires AutomationRegistryState {
+    public(friend) fun cancel_task(owner: &signer, id: u64): AutomationTaskMetaData acquires AutomationRegistryState {
         let state = borrow_global_mut(@supra_framework);
         assert!(enumerable_map::contains(&state.tasks, id), EAUTOMATION_TASK_NOT_FOUND);
 
@@ -212,7 +213,7 @@ module supra_framework::automation_registry_state {
 
     /// Update Automation gas limit.
     /// If the committed gas amount for the next epoch is greater then the new gas limit, then error is reported.
-    public (friend) fun update_automation_gas_limit(
+    public(friend) fun update_automation_gas_limit(
         supra_framework: &signer,
         automation_gas_limit: u64
     ) acquires AutomationRegistryState {
@@ -232,21 +233,16 @@ module supra_framework::automation_registry_state {
     public(friend) fun get_active_task_ids(): vector acquires AutomationRegistryState {
         let state = borrow_global(@supra_framework);
 
-        let active_task_ids = vector[];
-        let ids = enumerable_map::get_map_list(&state.tasks);
-
-        vector::for_each(ids, |id| {
-            let task = enumerable_map::get_value_ref(&state.tasks, id);
-            if (task.state != PENDING) {
-                vector::push_back(&mut active_task_ids, id);
-            };
-        });
-        return active_task_ids
+        enumerable_map::filter_map(&state.tasks, |task| {
+            let task: AutomationTaskMetaData = task; // we need to define task type here to avoid compiler error
+            if (task.state != PENDING) (true, task.id)
+            else (false, task.id)
+        })
     }
 
     /// Retrieves the details of a automation task entry by its ID.
     /// Error will be returned if entry with specified ID does not exist.
-    public (friend) fun get_task_details(id: u64): AutomationTaskMetaData acquires AutomationRegistryState {
+    public(friend) fun get_task_details(id: u64): AutomationTaskMetaData acquires AutomationRegistryState {
         let automation_task_metadata = borrow_global(@supra_framework);
         assert!(enumerable_map::contains(&automation_task_metadata.tasks, id), EAUTOMATION_TASK_NOT_FOUND);
         enumerable_map::get_value(&automation_task_metadata.tasks, id)
@@ -258,10 +254,11 @@ module supra_framework::automation_registry_state {
         if (enumerable_map::contains(&automation_task_metadata.tasks, id)) {
             let value = enumerable_map::get_value_ref(&automation_task_metadata.tasks, id);
             value.state != PENDING
-        } else  {
+        } else {
             false
         }
     }
+
     #[test_only]
     fun has_task_with_id(id: u64): bool acquires AutomationRegistryState {
         let automation_task_metadata = borrow_global(@supra_framework);
@@ -269,7 +266,7 @@ module supra_framework::automation_registry_state {
     }
 
     /// Returns next task index in registry
-    public (friend) fun get_next_task_index(): u64 acquires AutomationRegistryState {
+    public(friend) fun get_next_task_index(): u64 acquires AutomationRegistryState {
         let state = borrow_global(@supra_framework);
         state.current_index
     }
@@ -335,11 +332,11 @@ module supra_framework::automation_registry_state {
         let account = account::create_account_for_test(@0x123456);
         register(&account,
             PAYLOAD,
-        100,
-        10,
-        20,
-        1,
-        PARENT_HASH,
+            100,
+            10,
+            20,
+            1,
+            PARENT_HASH,
         );
         assert!(1 == get_next_task_index(), 1);
         assert!(10 == get_gas_committed_for_next_epoch(), 1)