diff --git a/precompile/binaries/minlib/bit_vector.mv b/precompile/binaries/minlib/bit_vector.mv index 78e98478..ef4f3da0 100644 Binary files a/precompile/binaries/minlib/bit_vector.mv and b/precompile/binaries/minlib/bit_vector.mv differ diff --git a/precompile/binaries/minlib/capability.mv b/precompile/binaries/minlib/capability.mv index 096769c1..6e66ca73 100644 Binary files a/precompile/binaries/minlib/capability.mv and b/precompile/binaries/minlib/capability.mv differ diff --git a/precompile/binaries/minlib/code.mv b/precompile/binaries/minlib/code.mv index 7b18283b..84d29c0f 100644 Binary files a/precompile/binaries/minlib/code.mv and b/precompile/binaries/minlib/code.mv differ diff --git a/precompile/binaries/minlib/coin.mv b/precompile/binaries/minlib/coin.mv index c694fbf4..840a881c 100644 Binary files a/precompile/binaries/minlib/coin.mv and b/precompile/binaries/minlib/coin.mv differ diff --git a/precompile/binaries/minlib/collection.mv b/precompile/binaries/minlib/collection.mv index 13b80252..47c5fe56 100644 Binary files a/precompile/binaries/minlib/collection.mv and b/precompile/binaries/minlib/collection.mv differ diff --git a/precompile/binaries/minlib/compare.mv b/precompile/binaries/minlib/compare.mv index faf00532..1bb2dfa7 100644 Binary files a/precompile/binaries/minlib/compare.mv and b/precompile/binaries/minlib/compare.mv differ diff --git a/precompile/binaries/minlib/cosmos.mv b/precompile/binaries/minlib/cosmos.mv index e6412050..676bd2f3 100644 Binary files a/precompile/binaries/minlib/cosmos.mv and b/precompile/binaries/minlib/cosmos.mv differ diff --git a/precompile/binaries/minlib/decimal128.mv b/precompile/binaries/minlib/decimal128.mv index 112ec3bc..5d41ca0b 100644 Binary files a/precompile/binaries/minlib/decimal128.mv and b/precompile/binaries/minlib/decimal128.mv differ diff --git a/precompile/binaries/minlib/decimal256.mv b/precompile/binaries/minlib/decimal256.mv index 8edf72ec..3cd6a29b 100644 Binary files a/precompile/binaries/minlib/decimal256.mv and b/precompile/binaries/minlib/decimal256.mv differ diff --git a/precompile/binaries/minlib/dex.mv b/precompile/binaries/minlib/dex.mv index 38c58d12..3bf0e544 100644 Binary files a/precompile/binaries/minlib/dex.mv and b/precompile/binaries/minlib/dex.mv differ diff --git a/precompile/binaries/minlib/dispatchable_fungible_asset.mv b/precompile/binaries/minlib/dispatchable_fungible_asset.mv index 86d8f9a4..c0fe1480 100644 Binary files a/precompile/binaries/minlib/dispatchable_fungible_asset.mv and b/precompile/binaries/minlib/dispatchable_fungible_asset.mv differ diff --git a/precompile/binaries/minlib/fixed_point32.mv b/precompile/binaries/minlib/fixed_point32.mv index 2dbe431d..4975febe 100644 Binary files a/precompile/binaries/minlib/fixed_point32.mv and b/precompile/binaries/minlib/fixed_point32.mv differ diff --git a/precompile/binaries/minlib/fixed_point64.mv b/precompile/binaries/minlib/fixed_point64.mv index 0ec95133..144460a3 100644 Binary files a/precompile/binaries/minlib/fixed_point64.mv and b/precompile/binaries/minlib/fixed_point64.mv differ diff --git a/precompile/binaries/minlib/from_bcs.mv b/precompile/binaries/minlib/from_bcs.mv index 84d67ba7..03ebbff5 100644 Binary files a/precompile/binaries/minlib/from_bcs.mv and b/precompile/binaries/minlib/from_bcs.mv differ diff --git a/precompile/binaries/minlib/function_info.mv b/precompile/binaries/minlib/function_info.mv index 74cc4e32..3f34df0b 100644 Binary files a/precompile/binaries/minlib/function_info.mv and b/precompile/binaries/minlib/function_info.mv differ diff --git a/precompile/binaries/minlib/fungible_asset.mv b/precompile/binaries/minlib/fungible_asset.mv index 9460e21d..9700a489 100644 Binary files a/precompile/binaries/minlib/fungible_asset.mv and b/precompile/binaries/minlib/fungible_asset.mv differ diff --git a/precompile/binaries/minlib/guid.mv b/precompile/binaries/minlib/guid.mv index ec4d7657..6132b511 100644 Binary files a/precompile/binaries/minlib/guid.mv and b/precompile/binaries/minlib/guid.mv differ diff --git a/precompile/binaries/minlib/hex.mv b/precompile/binaries/minlib/hex.mv index 4a02b76d..f6836ece 100644 Binary files a/precompile/binaries/minlib/hex.mv and b/precompile/binaries/minlib/hex.mv differ diff --git a/precompile/binaries/minlib/initia_nft.mv b/precompile/binaries/minlib/initia_nft.mv index 3ef0dc39..8d7041e3 100644 Binary files a/precompile/binaries/minlib/initia_nft.mv and b/precompile/binaries/minlib/initia_nft.mv differ diff --git a/precompile/binaries/minlib/managed_coin.mv b/precompile/binaries/minlib/managed_coin.mv index fb0f8197..d2fae891 100644 Binary files a/precompile/binaries/minlib/managed_coin.mv and b/precompile/binaries/minlib/managed_coin.mv differ diff --git a/precompile/binaries/minlib/multisig.mv b/precompile/binaries/minlib/multisig.mv index b912584b..12f10e1d 100644 Binary files a/precompile/binaries/minlib/multisig.mv and b/precompile/binaries/minlib/multisig.mv differ diff --git a/precompile/binaries/minlib/nft.mv b/precompile/binaries/minlib/nft.mv index 8f229b3f..4393d432 100644 Binary files a/precompile/binaries/minlib/nft.mv and b/precompile/binaries/minlib/nft.mv differ diff --git a/precompile/binaries/minlib/object_code_deployment.mv b/precompile/binaries/minlib/object_code_deployment.mv index ddafe15e..1cdc49ed 100644 Binary files a/precompile/binaries/minlib/object_code_deployment.mv and b/precompile/binaries/minlib/object_code_deployment.mv differ diff --git a/precompile/binaries/minlib/option.mv b/precompile/binaries/minlib/option.mv index c3631ce7..866c92c6 100644 Binary files a/precompile/binaries/minlib/option.mv and b/precompile/binaries/minlib/option.mv differ diff --git a/precompile/binaries/minlib/primary_fungible_store.mv b/precompile/binaries/minlib/primary_fungible_store.mv index 820ce278..ebf3a57b 100644 Binary files a/precompile/binaries/minlib/primary_fungible_store.mv and b/precompile/binaries/minlib/primary_fungible_store.mv differ diff --git a/precompile/binaries/minlib/query.mv b/precompile/binaries/minlib/query.mv index 6262f18e..0ccc67c8 100644 Binary files a/precompile/binaries/minlib/query.mv and b/precompile/binaries/minlib/query.mv differ diff --git a/precompile/binaries/minlib/simple_map.mv b/precompile/binaries/minlib/simple_map.mv index bab51579..50b61865 100644 Binary files a/precompile/binaries/minlib/simple_map.mv and b/precompile/binaries/minlib/simple_map.mv differ diff --git a/precompile/binaries/minlib/simple_nft.mv b/precompile/binaries/minlib/simple_nft.mv index 067e394e..dbca3fec 100644 Binary files a/precompile/binaries/minlib/simple_nft.mv and b/precompile/binaries/minlib/simple_nft.mv differ diff --git a/precompile/binaries/minlib/soul_bound_token.mv b/precompile/binaries/minlib/soul_bound_token.mv index 49742b74..b0062af0 100644 Binary files a/precompile/binaries/minlib/soul_bound_token.mv and b/precompile/binaries/minlib/soul_bound_token.mv differ diff --git a/precompile/binaries/minlib/string.mv b/precompile/binaries/minlib/string.mv index 8694fec0..198e4119 100644 Binary files a/precompile/binaries/minlib/string.mv and b/precompile/binaries/minlib/string.mv differ diff --git a/precompile/binaries/minlib/table.mv b/precompile/binaries/minlib/table.mv index ced1ac57..8c1f76eb 100644 Binary files a/precompile/binaries/minlib/table.mv and b/precompile/binaries/minlib/table.mv differ diff --git a/precompile/binaries/minlib/vector.mv b/precompile/binaries/minlib/vector.mv index 910195b9..d697ecd0 100644 Binary files a/precompile/binaries/minlib/vector.mv and b/precompile/binaries/minlib/vector.mv differ diff --git a/precompile/binaries/minlib/vip_score.mv b/precompile/binaries/minlib/vip_score.mv index 966b38ee..ad469d6e 100644 Binary files a/precompile/binaries/minlib/vip_score.mv and b/precompile/binaries/minlib/vip_score.mv differ diff --git a/precompile/binaries/stdlib/bit_vector.mv b/precompile/binaries/stdlib/bit_vector.mv index 78e98478..ef4f3da0 100644 Binary files a/precompile/binaries/stdlib/bit_vector.mv and b/precompile/binaries/stdlib/bit_vector.mv differ diff --git a/precompile/binaries/stdlib/capability.mv b/precompile/binaries/stdlib/capability.mv index 096769c1..6e66ca73 100644 Binary files a/precompile/binaries/stdlib/capability.mv and b/precompile/binaries/stdlib/capability.mv differ diff --git a/precompile/binaries/stdlib/code.mv b/precompile/binaries/stdlib/code.mv index 7b18283b..84d29c0f 100644 Binary files a/precompile/binaries/stdlib/code.mv and b/precompile/binaries/stdlib/code.mv differ diff --git a/precompile/binaries/stdlib/coin.mv b/precompile/binaries/stdlib/coin.mv index faba5e2a..3fceeb54 100644 Binary files a/precompile/binaries/stdlib/coin.mv and b/precompile/binaries/stdlib/coin.mv differ diff --git a/precompile/binaries/stdlib/collection.mv b/precompile/binaries/stdlib/collection.mv index 13b80252..47c5fe56 100644 Binary files a/precompile/binaries/stdlib/collection.mv and b/precompile/binaries/stdlib/collection.mv differ diff --git a/precompile/binaries/stdlib/compare.mv b/precompile/binaries/stdlib/compare.mv index faf00532..1bb2dfa7 100644 Binary files a/precompile/binaries/stdlib/compare.mv and b/precompile/binaries/stdlib/compare.mv differ diff --git a/precompile/binaries/stdlib/cosmos.mv b/precompile/binaries/stdlib/cosmos.mv index e6412050..676bd2f3 100644 Binary files a/precompile/binaries/stdlib/cosmos.mv and b/precompile/binaries/stdlib/cosmos.mv differ diff --git a/precompile/binaries/stdlib/decimal128.mv b/precompile/binaries/stdlib/decimal128.mv index bfda3788..6424596b 100644 Binary files a/precompile/binaries/stdlib/decimal128.mv and b/precompile/binaries/stdlib/decimal128.mv differ diff --git a/precompile/binaries/stdlib/decimal256.mv b/precompile/binaries/stdlib/decimal256.mv index 105c0edd..ee9acdf0 100644 Binary files a/precompile/binaries/stdlib/decimal256.mv and b/precompile/binaries/stdlib/decimal256.mv differ diff --git a/precompile/binaries/stdlib/dex.mv b/precompile/binaries/stdlib/dex.mv index 38c58d12..3bf0e544 100644 Binary files a/precompile/binaries/stdlib/dex.mv and b/precompile/binaries/stdlib/dex.mv differ diff --git a/precompile/binaries/stdlib/dispatchable_fungible_asset.mv b/precompile/binaries/stdlib/dispatchable_fungible_asset.mv index 86d8f9a4..c0fe1480 100644 Binary files a/precompile/binaries/stdlib/dispatchable_fungible_asset.mv and b/precompile/binaries/stdlib/dispatchable_fungible_asset.mv differ diff --git a/precompile/binaries/stdlib/fixed_point32.mv b/precompile/binaries/stdlib/fixed_point32.mv index 2dbe431d..4975febe 100644 Binary files a/precompile/binaries/stdlib/fixed_point32.mv and b/precompile/binaries/stdlib/fixed_point32.mv differ diff --git a/precompile/binaries/stdlib/fixed_point64.mv b/precompile/binaries/stdlib/fixed_point64.mv index 0ec95133..144460a3 100644 Binary files a/precompile/binaries/stdlib/fixed_point64.mv and b/precompile/binaries/stdlib/fixed_point64.mv differ diff --git a/precompile/binaries/stdlib/from_bcs.mv b/precompile/binaries/stdlib/from_bcs.mv index 84d67ba7..03ebbff5 100644 Binary files a/precompile/binaries/stdlib/from_bcs.mv and b/precompile/binaries/stdlib/from_bcs.mv differ diff --git a/precompile/binaries/stdlib/function_info.mv b/precompile/binaries/stdlib/function_info.mv index 74cc4e32..3f34df0b 100644 Binary files a/precompile/binaries/stdlib/function_info.mv and b/precompile/binaries/stdlib/function_info.mv differ diff --git a/precompile/binaries/stdlib/fungible_asset.mv b/precompile/binaries/stdlib/fungible_asset.mv index 9460e21d..9700a489 100644 Binary files a/precompile/binaries/stdlib/fungible_asset.mv and b/precompile/binaries/stdlib/fungible_asset.mv differ diff --git a/precompile/binaries/stdlib/guid.mv b/precompile/binaries/stdlib/guid.mv index ec4d7657..6132b511 100644 Binary files a/precompile/binaries/stdlib/guid.mv and b/precompile/binaries/stdlib/guid.mv differ diff --git a/precompile/binaries/stdlib/hex.mv b/precompile/binaries/stdlib/hex.mv index 4a02b76d..f6836ece 100644 Binary files a/precompile/binaries/stdlib/hex.mv and b/precompile/binaries/stdlib/hex.mv differ diff --git a/precompile/binaries/stdlib/initia_nft.mv b/precompile/binaries/stdlib/initia_nft.mv index 3ef0dc39..8d7041e3 100644 Binary files a/precompile/binaries/stdlib/initia_nft.mv and b/precompile/binaries/stdlib/initia_nft.mv differ diff --git a/precompile/binaries/stdlib/managed_coin.mv b/precompile/binaries/stdlib/managed_coin.mv index fb0f8197..d2fae891 100644 Binary files a/precompile/binaries/stdlib/managed_coin.mv and b/precompile/binaries/stdlib/managed_coin.mv differ diff --git a/precompile/binaries/stdlib/minitswap.mv b/precompile/binaries/stdlib/minitswap.mv index 1070686c..afeaa97d 100644 Binary files a/precompile/binaries/stdlib/minitswap.mv and b/precompile/binaries/stdlib/minitswap.mv differ diff --git a/precompile/binaries/stdlib/multisig.mv b/precompile/binaries/stdlib/multisig.mv index b912584b..12f10e1d 100644 Binary files a/precompile/binaries/stdlib/multisig.mv and b/precompile/binaries/stdlib/multisig.mv differ diff --git a/precompile/binaries/stdlib/nft.mv b/precompile/binaries/stdlib/nft.mv index 8f229b3f..4393d432 100644 Binary files a/precompile/binaries/stdlib/nft.mv and b/precompile/binaries/stdlib/nft.mv differ diff --git a/precompile/binaries/stdlib/object_code_deployment.mv b/precompile/binaries/stdlib/object_code_deployment.mv index 5240b20a..611b9beb 100644 Binary files a/precompile/binaries/stdlib/object_code_deployment.mv and b/precompile/binaries/stdlib/object_code_deployment.mv differ diff --git a/precompile/binaries/stdlib/option.mv b/precompile/binaries/stdlib/option.mv index c3631ce7..866c92c6 100644 Binary files a/precompile/binaries/stdlib/option.mv and b/precompile/binaries/stdlib/option.mv differ diff --git a/precompile/binaries/stdlib/primary_fungible_store.mv b/precompile/binaries/stdlib/primary_fungible_store.mv index 820ce278..ebf3a57b 100644 Binary files a/precompile/binaries/stdlib/primary_fungible_store.mv and b/precompile/binaries/stdlib/primary_fungible_store.mv differ diff --git a/precompile/binaries/stdlib/query.mv b/precompile/binaries/stdlib/query.mv index 6262f18e..0ccc67c8 100644 Binary files a/precompile/binaries/stdlib/query.mv and b/precompile/binaries/stdlib/query.mv differ diff --git a/precompile/binaries/stdlib/simple_map.mv b/precompile/binaries/stdlib/simple_map.mv index bab51579..50b61865 100644 Binary files a/precompile/binaries/stdlib/simple_map.mv and b/precompile/binaries/stdlib/simple_map.mv differ diff --git a/precompile/binaries/stdlib/simple_nft.mv b/precompile/binaries/stdlib/simple_nft.mv index 067e394e..dbca3fec 100644 Binary files a/precompile/binaries/stdlib/simple_nft.mv and b/precompile/binaries/stdlib/simple_nft.mv differ diff --git a/precompile/binaries/stdlib/soul_bound_token.mv b/precompile/binaries/stdlib/soul_bound_token.mv index 49742b74..b0062af0 100644 Binary files a/precompile/binaries/stdlib/soul_bound_token.mv and b/precompile/binaries/stdlib/soul_bound_token.mv differ diff --git a/precompile/binaries/stdlib/stableswap.mv b/precompile/binaries/stdlib/stableswap.mv index b0389f9a..94421e52 100644 Binary files a/precompile/binaries/stdlib/stableswap.mv and b/precompile/binaries/stdlib/stableswap.mv differ diff --git a/precompile/binaries/stdlib/staking.mv b/precompile/binaries/stdlib/staking.mv index 4d637b4f..720fa737 100644 Binary files a/precompile/binaries/stdlib/staking.mv and b/precompile/binaries/stdlib/staking.mv differ diff --git a/precompile/binaries/stdlib/string.mv b/precompile/binaries/stdlib/string.mv index 8694fec0..198e4119 100644 Binary files a/precompile/binaries/stdlib/string.mv and b/precompile/binaries/stdlib/string.mv differ diff --git a/precompile/binaries/stdlib/table.mv b/precompile/binaries/stdlib/table.mv index ced1ac57..8c1f76eb 100644 Binary files a/precompile/binaries/stdlib/table.mv and b/precompile/binaries/stdlib/table.mv differ diff --git a/precompile/binaries/stdlib/vector.mv b/precompile/binaries/stdlib/vector.mv index 910195b9..d697ecd0 100644 Binary files a/precompile/binaries/stdlib/vector.mv and b/precompile/binaries/stdlib/vector.mv differ diff --git a/precompile/modules/initia_stdlib/sources/multisig.move b/precompile/modules/initia_stdlib/sources/multisig.move index 9cbea4e4..727967f5 100644 --- a/precompile/modules/initia_stdlib/sources/multisig.move +++ b/precompile/modules/initia_stdlib/sources/multisig.move @@ -656,7 +656,7 @@ module initia_std::multisig { } #[test(account1 = @0x101, account2 = @0x102, account3 = @0x103)] - #[expected_failure(abort_code = 0x10000, location = simple_map)] + #[expected_failure(abort_code = 0x10001, location = simple_map)] fun duplicated_member( account1: signer, account2: signer, diff --git a/precompile/modules/initia_stdlib/sources/simple_map.move b/precompile/modules/initia_stdlib/sources/simple_map.move index afe08c43..df9d3418 100644 --- a/precompile/modules/initia_stdlib/sources/simple_map.move +++ b/precompile/modules/initia_stdlib/sources/simple_map.move @@ -1,17 +1,18 @@ -/// This module provides a solution for sorted maps, that is it has the properties that +/// This module provides a solution for unsorted maps, that is it has the properties that /// 1) Keys point to Values /// 2) Each Key must be unique -/// 3) A Key can be found within O(Log N) time -/// 4) The data is stored as a sorted by Key +/// 3) A Key can be found within O(N) time +/// 4) The keys are unsorted. /// 5) Adds and removals take O(N) time module initia_std::simple_map { use std::error; use std::option; use std::vector; - use initia_std::comparator; - const EKEY_ALREADY_EXISTS: u64 = 0; - const EKEY_NOT_FOUND: u64 = 1; + /// Map key already exists + const EKEY_ALREADY_EXISTS: u64 = 1; + /// Map key is not found + const EKEY_NOT_FOUND: u64 = 2; struct SimpleMap has copy, drop, store { data: vector>, @@ -22,130 +23,198 @@ module initia_std::simple_map { value: Value, } - public fun length(map: &SimpleMap): u64 { - vector::length(&map.data) + public fun length(self: &SimpleMap): u64 { + vector::length(&self.data) } - public fun create(): SimpleMap { + /// Create an empty SimpleMap. + public fun new(): SimpleMap { SimpleMap { data: vector::empty(), } } + /// Create a SimpleMap from a vector of keys and values. The keys must be unique. + public fun new_from( + keys: vector, values: vector, + ): SimpleMap { + let map = new(); + add_all(&mut map, keys, values); + map + } + + #[deprecated] + /// Create an empty SimpleMap. + /// This function is deprecated, use `new` instead. + public fun create(): SimpleMap { + new() + } + public fun borrow( - map: &SimpleMap, key: &Key, + self: &SimpleMap, + key: &Key, ): &Value { - let (maybe_idx, _) = find(map, key); - assert!( - option::is_some(&maybe_idx), - error::invalid_argument(EKEY_NOT_FOUND), - ); + let maybe_idx = find(self, key); + assert!(option::is_some(&maybe_idx), error::invalid_argument(EKEY_NOT_FOUND)); let idx = option::extract(&mut maybe_idx); - &vector::borrow(&map.data, idx).value + &vector::borrow(&self.data, idx).value } public fun borrow_mut( - map: &mut SimpleMap, key: &Key, + self: &mut SimpleMap, + key: &Key, ): &mut Value { - let (maybe_idx, _) = find(map, key); - assert!( - option::is_some(&maybe_idx), - error::invalid_argument(EKEY_NOT_FOUND), - ); + let maybe_idx = find(self, key); + assert!(option::is_some(&maybe_idx), error::invalid_argument(EKEY_NOT_FOUND)); let idx = option::extract(&mut maybe_idx); - &mut vector::borrow_mut(&mut map.data, idx).value + &mut vector::borrow_mut(&mut self.data, idx).value } public fun contains_key( - map: &SimpleMap, key: &Key, + self: &SimpleMap, + key: &Key, ): bool { - let (maybe_idx, _) = find(map, key); + let maybe_idx = find(self, key); option::is_some(&maybe_idx) } public fun destroy_empty( - map: SimpleMap + self: SimpleMap ) { - let SimpleMap { data } = map; + let SimpleMap { data } = self; vector::destroy_empty(data); } + /// Add a key/value pair to the map. The key must not already exist. public fun add( - map: &mut SimpleMap, + self: &mut SimpleMap, key: Key, value: Value, ) { - let (maybe_idx, maybe_placement) = find(map, &key); - assert!( - option::is_none(&maybe_idx), - error::invalid_argument(EKEY_ALREADY_EXISTS), - ); - - // Append to the end and then swap elements until the list is ordered again - vector::push_back(&mut map.data, Element { key, value }); + let maybe_idx = find(self, &key); + assert!(option::is_none(&maybe_idx), error::invalid_argument(EKEY_ALREADY_EXISTS)); - let placement = option::extract(&mut maybe_placement); - let end = vector::length(&map.data) - 1; - while (placement < end) { - vector::swap(&mut map.data, placement, end); - placement = placement + 1; - }; + vector::push_back(&mut self.data, Element { key, value }); } - public fun remove( - map: &mut SimpleMap, key: &Key, - ): (Key, Value) { - let (maybe_idx, _) = find(map, key); - assert!( - option::is_some(&maybe_idx), - error::invalid_argument(EKEY_NOT_FOUND), + /// Add multiple key/value pairs to the map. The keys must not already exist. + public fun add_all( + self: &mut SimpleMap, + keys: vector, + values: vector, + ) { + vector::zip( + keys, values, + |key, value| { + add(self, key, value); + } ); + } - let placement = option::extract(&mut maybe_idx); - let end = vector::length(&map.data) - 1; - - while (placement < end) { - vector::swap( - &mut map.data, - placement, - placement + 1, - ); - placement = placement + 1; + /// Insert key/value pair or update an existing key to a new value + public fun upsert( + self: &mut SimpleMap, + key: Key, + value: Value + ): (std::option::Option, std::option::Option) { + let data = &mut self.data; + let len = vector::length(data); + let i = 0; + while (i < len) { + let element = vector::borrow(data, i); + if (&element.key == &key) { + vector::push_back(data, Element { key, value }); + vector::swap(data, i, len); + let Element { key, value } = vector::pop_back(data); + return (std::option::some(key), std::option::some(value)) + }; + i = i + 1; }; + vector::push_back(&mut self.data, Element { key, value }); + (std::option::none(), std::option::none()) + } - let Element { key, value } = vector::pop_back(&mut map.data); - (key, value) + /// Return all keys in the map. This requires keys to be copyable. + public fun keys(self: &SimpleMap): vector { + vector::map_ref( + &self.data, + |e| { + let e: &Element = e; + e.key + }, + ) } - fun find( - map: &SimpleMap, key: &Key, - ): (option::Option, option::Option) { - let length = vector::length(&map.data); + /// Return all values in the map. This requires values to be copyable. + public fun values(self: &SimpleMap): vector { + vector::map_ref( + &self.data, + |e| { + let e: &Element = e; + e.value + }, + ) + } - if (length == 0) { - return (option::none(), option::some(0)) - }; + /// Transform the map into two vectors with the keys and values respectively + /// Primarily used to destroy a map + public fun to_vec_pair( + self: SimpleMap + ): (vector, vector) { + let keys: vector = vector::empty(); + let values: vector = vector::empty(); + let SimpleMap { data } = self; + vector::for_each( + data, + |e| { + let Element { key, value } = e; + vector::push_back(&mut keys, key); + vector::push_back(&mut values, value); + }, + ); + (keys, values) + } - let left = 0; - let right = length; + /// For maps that cannot be dropped this is a utility to destroy them + /// using lambdas to destroy the individual keys and values. + public inline fun destroy( + self: SimpleMap, + dk: |Key|, + dv: |Value| + ) { + let (keys, values) = to_vec_pair(self); + vector::destroy(keys, |_k| dk(_k)); + vector::destroy(values, |_v| dv(_v)); + } - while (left != right) { - let mid = (left + right) / 2; - let potential_key = &vector::borrow(&map.data, mid).key; - if (comparator::is_smaller_than(&comparator::compare(potential_key, key))) { - left = mid + 1; - } else { - right = mid; + /// Remove a key/value pair from the map. The key must exist. + public fun remove( + self: &mut SimpleMap, + key: &Key, + ): (Key, Value) { + let maybe_idx = find(self, key); + assert!(option::is_some(&maybe_idx), error::invalid_argument(EKEY_NOT_FOUND)); + let placement = option::extract(&mut maybe_idx); + let Element { key, value } = vector::swap_remove(&mut self.data, placement); + (key, value) + } + + fun find( + self: &SimpleMap, + key: &Key, + ): option::Option { + let leng = vector::length(&self.data); + let i = 0; + while (i < leng) { + let element = vector::borrow(&self.data, i); + if (&element.key == key) { + return option::some(i) }; + i = i + 1; }; - - if (left != length && key == &vector::borrow(&map.data, left).key) { - (option::some(left), option::none()) - } else { - (option::none(), option::some(left)) - } + option::none() } #[test] - public fun add_remove_many() { + public fun test_add_remove_many() { let map = create(); assert!(length(&map) == 0, 0); @@ -178,41 +247,45 @@ module initia_std::simple_map { } #[test] - public fun test_several() { + public fun test_add_all() { let map = create(); - add(&mut map, 6, 6); - add(&mut map, 1, 1); - add(&mut map, 5, 5); - add(&mut map, 2, 2); - add(&mut map, 3, 3); - add(&mut map, 0, 0); - add(&mut map, 7, 7); - add(&mut map, 4, 4); - - let idx = 0; - while (idx < vector::length(&map.data)) { - assert!( - idx == vector::borrow(&map.data, idx).key, - idx, - ); - idx = idx + 1; - }; - remove(&mut map, &0); + assert!(length(&map) == 0, 0); + add_all(&mut map, vector[1, 2, 3], vector[10, 20, 30]); + assert!(length(&map) == 3, 1); + assert!(borrow(&map, &1) == &10, 2); + assert!(borrow(&map, &2) == &20, 3); + assert!(borrow(&map, &3) == &30, 4); + remove(&mut map, &1); remove(&mut map, &2); remove(&mut map, &3); - remove(&mut map, &4); - remove(&mut map, &5); - remove(&mut map, &6); - remove(&mut map, &7); - destroy_empty(map); } + #[test] + public fun test_keys() { + let map = create(); + assert!(keys(&map) == vector[], 0); + add(&mut map, 2, 1); + add(&mut map, 3, 1); + + assert!(keys(&map) == vector[2, 3], 0); + } + + #[test] + public fun test_values() { + let map = create(); + assert!(values(&map) == vector[], 0); + add(&mut map, 2, 1); + add(&mut map, 3, 2); + + assert!(values(&map) == vector[1, 2], 0); + } + #[test] #[expected_failure] - public fun add_twice() { + public fun test_add_twice() { let map = create(); add(&mut map, 3, 1); add(&mut map, 3, 1); @@ -223,7 +296,7 @@ module initia_std::simple_map { #[test] #[expected_failure] - public fun remove_twice() { + public fun test_remove_twice() { let map = create(); add(&mut map, 3, 1); remove(&mut map, &3); @@ -231,4 +304,28 @@ module initia_std::simple_map { destroy_empty(map); } + + #[test] + public fun test_upsert_test() { + let map = create(); + // test adding 3 elements using upsert + upsert(&mut map, 1, 1); + upsert(&mut map, 2, 2); + upsert(&mut map, 3, 3); + + assert!(length(&map) == 3, 0); + assert!(contains_key(&map, &1), 1); + assert!(contains_key(&map, &2), 2); + assert!(contains_key(&map, &3), 3); + assert!(borrow(&map, &1) == &1, 4); + assert!(borrow(&map, &2) == &2, 5); + assert!(borrow(&map, &3) == &3, 6); + + // change mapping 1->1 to 1->4 + upsert(&mut map, 1, 4); + + assert!(length(&map) == 3, 7); + assert!(contains_key(&map, &1), 8); + assert!(borrow(&map, &1) == &4, 9); + } } diff --git a/precompile/modules/minitia_stdlib/sources/multisig.move b/precompile/modules/minitia_stdlib/sources/multisig.move index d65dd383..1c89016a 100644 --- a/precompile/modules/minitia_stdlib/sources/multisig.move +++ b/precompile/modules/minitia_stdlib/sources/multisig.move @@ -656,7 +656,7 @@ module minitia_std::multisig { } #[test(account1 = @0x101, account2 = @0x102, account3 = @0x103)] - #[expected_failure(abort_code = 0x10000, location = simple_map)] + #[expected_failure(abort_code = 0x10001, location = simple_map)] fun duplicated_member( account1: signer, account2: signer, diff --git a/precompile/modules/minitia_stdlib/sources/simple_map.move b/precompile/modules/minitia_stdlib/sources/simple_map.move index 5ba90407..8d4bae2e 100644 --- a/precompile/modules/minitia_stdlib/sources/simple_map.move +++ b/precompile/modules/minitia_stdlib/sources/simple_map.move @@ -1,17 +1,18 @@ -/// This module provides a solution for sorted maps, that is it has the properties that +/// This module provides a solution for unsorted maps, that is it has the properties that /// 1) Keys point to Values /// 2) Each Key must be unique -/// 3) A Key can be found within O(Log N) time -/// 4) The data is stored as a sorted by Key +/// 3) A Key can be found within O(N) time +/// 4) The keys are unsorted. /// 5) Adds and removals take O(N) time module minitia_std::simple_map { use std::error; use std::option; use std::vector; - use minitia_std::comparator; - const EKEY_ALREADY_EXISTS: u64 = 0; - const EKEY_NOT_FOUND: u64 = 1; + /// Map key already exists + const EKEY_ALREADY_EXISTS: u64 = 1; + /// Map key is not found + const EKEY_NOT_FOUND: u64 = 2; struct SimpleMap has copy, drop, store { data: vector>, @@ -22,130 +23,198 @@ module minitia_std::simple_map { value: Value, } - public fun length(map: &SimpleMap): u64 { - vector::length(&map.data) + public fun length(self: &SimpleMap): u64 { + vector::length(&self.data) } - public fun create(): SimpleMap { + /// Create an empty SimpleMap. + public fun new(): SimpleMap { SimpleMap { data: vector::empty(), } } + /// Create a SimpleMap from a vector of keys and values. The keys must be unique. + public fun new_from( + keys: vector, values: vector, + ): SimpleMap { + let map = new(); + add_all(&mut map, keys, values); + map + } + + #[deprecated] + /// Create an empty SimpleMap. + /// This function is deprecated, use `new` instead. + public fun create(): SimpleMap { + new() + } + public fun borrow( - map: &SimpleMap, key: &Key, + self: &SimpleMap, + key: &Key, ): &Value { - let (maybe_idx, _) = find(map, key); - assert!( - option::is_some(&maybe_idx), - error::invalid_argument(EKEY_NOT_FOUND), - ); + let maybe_idx = find(self, key); + assert!(option::is_some(&maybe_idx), error::invalid_argument(EKEY_NOT_FOUND)); let idx = option::extract(&mut maybe_idx); - &vector::borrow(&map.data, idx).value + &vector::borrow(&self.data, idx).value } public fun borrow_mut( - map: &mut SimpleMap, key: &Key, + self: &mut SimpleMap, + key: &Key, ): &mut Value { - let (maybe_idx, _) = find(map, key); - assert!( - option::is_some(&maybe_idx), - error::invalid_argument(EKEY_NOT_FOUND), - ); + let maybe_idx = find(self, key); + assert!(option::is_some(&maybe_idx), error::invalid_argument(EKEY_NOT_FOUND)); let idx = option::extract(&mut maybe_idx); - &mut vector::borrow_mut(&mut map.data, idx).value + &mut vector::borrow_mut(&mut self.data, idx).value } public fun contains_key( - map: &SimpleMap, key: &Key, + self: &SimpleMap, + key: &Key, ): bool { - let (maybe_idx, _) = find(map, key); + let maybe_idx = find(self, key); option::is_some(&maybe_idx) } public fun destroy_empty( - map: SimpleMap + self: SimpleMap ) { - let SimpleMap { data } = map; + let SimpleMap { data } = self; vector::destroy_empty(data); } + /// Add a key/value pair to the map. The key must not already exist. public fun add( - map: &mut SimpleMap, + self: &mut SimpleMap, key: Key, value: Value, ) { - let (maybe_idx, maybe_placement) = find(map, &key); - assert!( - option::is_none(&maybe_idx), - error::invalid_argument(EKEY_ALREADY_EXISTS), - ); - - // Append to the end and then swap elements until the list is ordered again - vector::push_back(&mut map.data, Element { key, value }); + let maybe_idx = find(self, &key); + assert!(option::is_none(&maybe_idx), error::invalid_argument(EKEY_ALREADY_EXISTS)); - let placement = option::extract(&mut maybe_placement); - let end = vector::length(&map.data) - 1; - while (placement < end) { - vector::swap(&mut map.data, placement, end); - placement = placement + 1; - }; + vector::push_back(&mut self.data, Element { key, value }); } - public fun remove( - map: &mut SimpleMap, key: &Key, - ): (Key, Value) { - let (maybe_idx, _) = find(map, key); - assert!( - option::is_some(&maybe_idx), - error::invalid_argument(EKEY_NOT_FOUND), + /// Add multiple key/value pairs to the map. The keys must not already exist. + public fun add_all( + self: &mut SimpleMap, + keys: vector, + values: vector, + ) { + vector::zip( + keys, values, + |key, value| { + add(self, key, value); + } ); + } - let placement = option::extract(&mut maybe_idx); - let end = vector::length(&map.data) - 1; - - while (placement < end) { - vector::swap( - &mut map.data, - placement, - placement + 1, - ); - placement = placement + 1; + /// Insert key/value pair or update an existing key to a new value + public fun upsert( + self: &mut SimpleMap, + key: Key, + value: Value + ): (std::option::Option, std::option::Option) { + let data = &mut self.data; + let len = vector::length(data); + let i = 0; + while (i < len) { + let element = vector::borrow(data, i); + if (&element.key == &key) { + vector::push_back(data, Element { key, value }); + vector::swap(data, i, len); + let Element { key, value } = vector::pop_back(data); + return (std::option::some(key), std::option::some(value)) + }; + i = i + 1; }; + vector::push_back(&mut self.data, Element { key, value }); + (std::option::none(), std::option::none()) + } - let Element { key, value } = vector::pop_back(&mut map.data); - (key, value) + /// Return all keys in the map. This requires keys to be copyable. + public fun keys(self: &SimpleMap): vector { + vector::map_ref( + &self.data, + |e| { + let e: &Element = e; + e.key + }, + ) } - fun find( - map: &SimpleMap, key: &Key, - ): (option::Option, option::Option) { - let length = vector::length(&map.data); + /// Return all values in the map. This requires values to be copyable. + public fun values(self: &SimpleMap): vector { + vector::map_ref( + &self.data, + |e| { + let e: &Element = e; + e.value + }, + ) + } - if (length == 0) { - return (option::none(), option::some(0)) - }; + /// Transform the map into two vectors with the keys and values respectively + /// Primarily used to destroy a map + public fun to_vec_pair( + self: SimpleMap + ): (vector, vector) { + let keys: vector = vector::empty(); + let values: vector = vector::empty(); + let SimpleMap { data } = self; + vector::for_each( + data, + |e| { + let Element { key, value } = e; + vector::push_back(&mut keys, key); + vector::push_back(&mut values, value); + }, + ); + (keys, values) + } - let left = 0; - let right = length; + /// For maps that cannot be dropped this is a utility to destroy them + /// using lambdas to destroy the individual keys and values. + public inline fun destroy( + self: SimpleMap, + dk: |Key|, + dv: |Value| + ) { + let (keys, values) = to_vec_pair(self); + vector::destroy(keys, |_k| dk(_k)); + vector::destroy(values, |_v| dv(_v)); + } - while (left != right) { - let mid = (left + right) / 2; - let potential_key = &vector::borrow(&map.data, mid).key; - if (comparator::is_smaller_than(&comparator::compare(potential_key, key))) { - left = mid + 1; - } else { - right = mid; + /// Remove a key/value pair from the map. The key must exist. + public fun remove( + self: &mut SimpleMap, + key: &Key, + ): (Key, Value) { + let maybe_idx = find(self, key); + assert!(option::is_some(&maybe_idx), error::invalid_argument(EKEY_NOT_FOUND)); + let placement = option::extract(&mut maybe_idx); + let Element { key, value } = vector::swap_remove(&mut self.data, placement); + (key, value) + } + + fun find( + self: &SimpleMap, + key: &Key, + ): option::Option { + let leng = vector::length(&self.data); + let i = 0; + while (i < leng) { + let element = vector::borrow(&self.data, i); + if (&element.key == key) { + return option::some(i) }; + i = i + 1; }; - - if (left != length && key == &vector::borrow(&map.data, left).key) { - (option::some(left), option::none()) - } else { - (option::none(), option::some(left)) - } + option::none() } #[test] - public fun add_remove_many() { + public fun test_add_remove_many() { let map = create(); assert!(length(&map) == 0, 0); @@ -178,41 +247,45 @@ module minitia_std::simple_map { } #[test] - public fun test_several() { + public fun test_add_all() { let map = create(); - add(&mut map, 6, 6); - add(&mut map, 1, 1); - add(&mut map, 5, 5); - add(&mut map, 2, 2); - add(&mut map, 3, 3); - add(&mut map, 0, 0); - add(&mut map, 7, 7); - add(&mut map, 4, 4); - - let idx = 0; - while (idx < vector::length(&map.data)) { - assert!( - idx == vector::borrow(&map.data, idx).key, - idx, - ); - idx = idx + 1; - }; - remove(&mut map, &0); + assert!(length(&map) == 0, 0); + add_all(&mut map, vector[1, 2, 3], vector[10, 20, 30]); + assert!(length(&map) == 3, 1); + assert!(borrow(&map, &1) == &10, 2); + assert!(borrow(&map, &2) == &20, 3); + assert!(borrow(&map, &3) == &30, 4); + remove(&mut map, &1); remove(&mut map, &2); remove(&mut map, &3); - remove(&mut map, &4); - remove(&mut map, &5); - remove(&mut map, &6); - remove(&mut map, &7); - destroy_empty(map); } + #[test] + public fun test_keys() { + let map = create(); + assert!(keys(&map) == vector[], 0); + add(&mut map, 2, 1); + add(&mut map, 3, 1); + + assert!(keys(&map) == vector[2, 3], 0); + } + + #[test] + public fun test_values() { + let map = create(); + assert!(values(&map) == vector[], 0); + add(&mut map, 2, 1); + add(&mut map, 3, 2); + + assert!(values(&map) == vector[1, 2], 0); + } + #[test] #[expected_failure] - public fun add_twice() { + public fun test_add_twice() { let map = create(); add(&mut map, 3, 1); add(&mut map, 3, 1); @@ -223,7 +296,7 @@ module minitia_std::simple_map { #[test] #[expected_failure] - public fun remove_twice() { + public fun test_remove_twice() { let map = create(); add(&mut map, 3, 1); remove(&mut map, &3); @@ -231,4 +304,28 @@ module minitia_std::simple_map { destroy_empty(map); } + + #[test] + public fun test_upsert_test() { + let map = create(); + // test adding 3 elements using upsert + upsert(&mut map, 1, 1); + upsert(&mut map, 2, 2); + upsert(&mut map, 3, 3); + + assert!(length(&map) == 3, 0); + assert!(contains_key(&map, &1), 1); + assert!(contains_key(&map, &2), 2); + assert!(contains_key(&map, &3), 3); + assert!(borrow(&map, &1) == &1, 4); + assert!(borrow(&map, &2) == &2, 5); + assert!(borrow(&map, &3) == &3, 6); + + // change mapping 1->1 to 1->4 + upsert(&mut map, 1, 4); + + assert!(length(&map) == 3, 7); + assert!(contains_key(&map, &1), 8); + assert!(borrow(&map, &1) == &4, 9); + } }