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)
diff --git a/aptos-move/framework/supra-stdlib/doc/enumerable_map.md b/aptos-move/framework/supra-stdlib/doc/enumerable_map.md
index dedf74812516f..87b8d8e8cc037 100644
--- a/aptos-move/framework/supra-stdlib/doc/enumerable_map.md
+++ b/aptos-move/framework/supra-stdlib/doc/enumerable_map.md
@@ -22,10 +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;
@@ -188,7 +197,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 +222,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 +249,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 +280,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 +292,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
 }
 
@@ -305,7 +315,7 @@ Update the value of a key thats already present in the Enumerable Map 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
 
@@ -314,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;
@@ -324,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
 }
 
@@ -348,7 +358,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 +405,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 +431,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,13 +456,38 @@ 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
 }
 
+ + + + +## 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)
+}
+
+ + +
@@ -471,7 +506,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 +531,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 +556,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 +581,255 @@ 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 = get_key_by_index(set, i);
+        f(*get_value_ref(set, key));
+        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 = 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
+    }
+}
+
+ + + +
+ + + +## Function `filter` + +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>
+
+ + + +
+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_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| {
+        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 dfc4c22d0895a..df2b6a67b2e4f 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 @@ -69,19 +69,20 @@ 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 - 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; @@ -91,11 +92,11 @@ 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 - public fun remove_value_bulk( + public fun remove_value_bulk( map: &mut EnumerableMap, keys: vector ): vector { @@ -122,57 +123,148 @@ 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 } + /// 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 { + 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 = get_key_by_index(set, i); + f(*get_value_ref(set, key)); + 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 = get_key_by_index(set, i); + f(get_value_ref(set, key)); + i = i + 1 + } + } + + /// 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 = get_key_by_index(set, i); + f(get_value_mut(set, key)); + 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 = get_key_by_index(set, i); + f(key, *get_value_ref(set, key)); + i = i + 1 + } + } + + /// 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| { + if (p(v)) vector::push_back(&mut result, *v); + }); + 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 { + 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); @@ -182,14 +274,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]); @@ -202,14 +287,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); @@ -224,14 +302,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]); @@ -244,14 +315,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); @@ -264,14 +328,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); @@ -279,4 +336,69 @@ 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 = get_enum_map(); + + let i = 1; + for_each_value_ref(&enum_map, |v| { + assert!(v == &i, 100); + i = i + 1; + }); + + let j = 1; + 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 }) + } + + #[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 }) + } + + #[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 }) + } }