From 4b4fc3606a000d3bff8272f00dd9510bce46bc1d Mon Sep 17 00:00:00 2001 From: murphy0612 Date: Thu, 21 Dec 2023 08:34:25 +0000 Subject: [PATCH 1/2] Add skip_list_u128, option_u128 module. Upgrade sui framework to mainnet-v1.15.1 --- sui/Move.lock | 6 +- sui/Move.toml | 2 +- sui/sources/linked_table.move | 31 +- sui/sources/option_u128.move | 83 +++++ sui/sources/skip_list.move | 15 + sui/sources/skip_list_u128.move | 640 ++++++++++++++++++++++++++++++++ 6 files changed, 763 insertions(+), 14 deletions(-) create mode 100644 sui/sources/option_u128.move create mode 100644 sui/sources/skip_list_u128.move diff --git a/sui/Move.lock b/sui/Move.lock index ad5ad77..f03f4ef 100644 --- a/sui/Move.lock +++ b/sui/Move.lock @@ -2,6 +2,8 @@ [move] version = 0 +manifest_digest = "A3A8D0CE24452F0F6AB1F7659366EC8994A4A6D8F29C331B04E88C1983483556" +deps_digest = "F8BBB0CCB2491CA29A3DF03D6F92277A4F3574266507ACD77214D37ECA3F3082" dependencies = [ { name = "Sui" }, @@ -9,11 +11,11 @@ dependencies = [ [[move.package]] name = "MoveStdlib" -source = { git = "https://github.com/MystenLabs/sui.git", rev = "mainnet-v1.6.3", subdir = "crates/sui-framework/packages/move-stdlib" } +source = { git = "https://github.com/MystenLabs/sui.git", rev = "mainnet-v1.15.1", subdir = "crates/sui-framework/packages/move-stdlib" } [[move.package]] name = "Sui" -source = { git = "https://github.com/MystenLabs/sui.git", rev = "mainnet-v1.6.3", subdir = "crates/sui-framework/packages/sui-framework" } +source = { git = "https://github.com/MystenLabs/sui.git", rev = "mainnet-v1.15.1", subdir = "crates/sui-framework/packages/sui-framework" } dependencies = [ { name = "MoveStdlib" }, diff --git a/sui/Move.toml b/sui/Move.toml index 039d775..bb1cc31 100644 --- a/sui/Move.toml +++ b/sui/Move.toml @@ -6,7 +6,7 @@ version = "1.1.0" published-at = "0xfacdeb69fc1354887ab4be6f8bd58b70a2c139ce85eb3cbc18b13013ff75ce73" [dependencies] -Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "mainnet-v1.6.3" } +Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "mainnet-v1.15.1" } [addresses] move_stl = "0xbe21a06129308e0495431d12286127897aff07a8ade3970495a4404d97f9eaaa" diff --git a/sui/sources/linked_table.move b/sui/sources/linked_table.move index c967049..18c450b 100644 --- a/sui/sources/linked_table.move +++ b/sui/sources/linked_table.move @@ -182,7 +182,7 @@ module move_stl::linked_table { #[test_only] use sui::tx_context; #[test_only] - use sui::transfer::transfer; + use sui::transfer; #[test] fun test_table_new() { @@ -195,6 +195,7 @@ module move_stl::linked_table { } #[test] + #[lint_allow(self_transfer)] fun test_table_push_front() { let ctx = &mut tx_context::dummy(); let table = new(ctx); @@ -227,10 +228,11 @@ module move_stl::linked_table { assert!(is_none(&node_3.prev), 0); assert!((is_some(&node_3.next) && (*option::borrow(&node_3.next) == 2)), 0); - transfer(table, tx_context::sender(ctx)); + transfer::transfer(table, tx_context::sender(ctx)); } #[test] + #[lint_allow(self_transfer)] fun test_table_push_back() { let ctx = &mut tx_context::dummy(); let table = new(ctx); @@ -263,10 +265,11 @@ module move_stl::linked_table { assert!((is_some(&node_3.prev) && (*option::borrow(&node_3.prev) == 2)), 0); assert!(is_none(&node_3.next), 0); - transfer(table, tx_context::sender(ctx)); + transfer::transfer(table, tx_context::sender(ctx)); } #[test] + #[lint_allow(self_transfer)] fun test_table_remove() { let ctx = &mut tx_context::dummy(); let table = new(ctx); @@ -317,10 +320,11 @@ module move_stl::linked_table { assert!(length(&table) == 6, 0); - transfer(table, tx_context::sender(ctx)); + transfer::transfer(table, tx_context::sender(ctx)); } #[test] + #[lint_allow(self_transfer)] fun test_table_insert_before() { let ctx = &mut tx_context::dummy(); let table = new(ctx); @@ -369,10 +373,11 @@ module move_stl::linked_table { assert!(*option::borrow(&table.head) == 1, 0); assert!(*option::borrow(&table.tail) == 10, 0); - transfer(table, tx_context::sender(ctx)); + transfer::transfer(table, tx_context::sender(ctx)); } #[test] + #[lint_allow(self_transfer)] fun test_table_insert_after() { let ctx = &mut tx_context::dummy(); let table = new(ctx); @@ -424,10 +429,11 @@ module move_stl::linked_table { assert!(*option::borrow(&table.head) == 2, 0); assert!(*option::borrow(&table.tail) == 11, 0); - transfer(table, tx_context::sender(ctx)); + transfer::transfer(table, tx_context::sender(ctx)); } #[test] + #[lint_allow(self_transfer)] fun test_table_push_back_bench() { let ctx = &mut tx_context::dummy(); let table = new(ctx); @@ -436,10 +442,11 @@ module move_stl::linked_table { push_back(&mut table, n, (n as u256)); n = n + 1; }; - transfer(table, tx_context::sender(ctx)); + transfer::transfer(table, tx_context::sender(ctx)); } #[test] + #[lint_allow(self_transfer)] fun test_table_push_front_bench() { let ctx = &mut tx_context::dummy(); let table = new(ctx); @@ -448,10 +455,11 @@ module move_stl::linked_table { push_front(&mut table, n, (n as u256)); n = n + 1; }; - transfer(table, tx_context::sender(ctx)); + transfer::transfer(table, tx_context::sender(ctx)); } #[test] + #[lint_allow(self_transfer)] fun test_table_insert_before_bench() { let ctx = &mut tx_context::dummy(); let table = new(ctx); @@ -464,10 +472,11 @@ module move_stl::linked_table { current_key = n; n = n - 1; }; - transfer(table, tx_context::sender(ctx)); + transfer::transfer(table, tx_context::sender(ctx)); } #[test] + #[lint_allow(self_transfer)] fun test_table_insert_after_bench() { let ctx = &mut tx_context::dummy(); let table = new(ctx); @@ -480,6 +489,6 @@ module move_stl::linked_table { current_key = n; n = n + 1; }; - transfer(table, tx_context::sender(ctx)); + transfer::transfer(table, tx_context::sender(ctx)); } -} \ No newline at end of file +} diff --git a/sui/sources/option_u128.move b/sui/sources/option_u128.move new file mode 100644 index 0000000..b8fa9e1 --- /dev/null +++ b/sui/sources/option_u128.move @@ -0,0 +1,83 @@ +module move_stl::option_u128 { + #[test_only] + use std::option; + + const EOptionU128IsNone: u64 = 0; + + struct OptionU128 has copy, drop, store { + is_none: bool, + v: u128 + } + + public fun some(v: u128): OptionU128 { + OptionU128 { + is_none: false, + v + } + } + + public fun none(): OptionU128 { + OptionU128 { + is_none: true, + v: 0 + } + } + + public fun borrow(opt: &OptionU128): u128 { + assert!(!opt.is_none, EOptionU128IsNone); + opt.v + } + + public fun borrow_mut(opt: &mut OptionU128): &mut u128 { + assert!(!opt.is_none, EOptionU128IsNone); + &mut opt.v + } + + public fun swap_or_fill(opt: &mut OptionU128, v: u128) { + opt.is_none = false; + opt.v = v; + } + + public fun is_some(opt: &OptionU128): bool { + !opt.is_none + } + + public fun is_none(opt: &OptionU128): bool { + opt.is_none + } + + public fun contains(opt: &OptionU128, e_ref: u128): bool { + if (opt.is_none) { + return false + }; + (opt.v == e_ref) + } + + public fun is_some_and_eq(opt: &OptionU128, v: u128): bool { + ((!opt.is_none) && (opt.v == v)) + } + + public fun is_some_and_lte(opt: &OptionU128, v: u128): bool { + (!opt.is_none) && (opt.v <= v) + } + + #[test] + fun test_opt() { + let a = some(10000u128); + let n = 0; + while (n < 10000) { + _ = borrow(&a); + n = n + 1; + }; + } + + #[test] + fun test_option_contains() { + let a = option::some(100000); + let n = 0; + while (n < 10000) { + option::contains(&a, &100000); + n = n + 1; + } + } +} diff --git a/sui/sources/skip_list.move b/sui/sources/skip_list.move index dbb85b9..c431096 100644 --- a/sui/sources/skip_list.move +++ b/sui/sources/skip_list.move @@ -9,6 +9,8 @@ module move_stl::skip_list { const ENodeAlreadyExist: u64 = 0; const ENodeDoesNotExist: u64 = 1; const ESkipListNotEmpty: u64 = 3; + + #[allow(unused_const)] const ESkipListIsEmpty: u64 = 4; /// The skip list. @@ -365,6 +367,7 @@ module move_stl::skip_list { } #[test_only] + #[lint_allow(self_transfer)] fun check_skip_list(list: &SkipList) { if (list.level == 0) { assert!(length(list) == 0, 0); @@ -434,6 +437,7 @@ module move_stl::skip_list { } #[test_only] + #[lint_allow(self_transfer)] fun get_all_socres(list: &SkipList): vector { let (opt_next_score,scores ) = (vector::borrow(&list.head, 0), vector::empty()); while (is_some(opt_next_score)) { @@ -446,6 +450,7 @@ module move_stl::skip_list { } #[test] + #[lint_allow(self_transfer)] fun test_new() { let ctx = &mut tx_context::dummy(); let skip_list = new(16, 2, 12345, ctx); @@ -454,6 +459,7 @@ module move_stl::skip_list { } #[test] + #[lint_allow(self_transfer)] fun test_create_node() { let ctx = &mut tx_context::dummy(); let skip_list = new(16, 2, 12345, ctx); @@ -468,6 +474,7 @@ module move_stl::skip_list { } #[test_only] + #[lint_allow(self_transfer)] fun add_node_for_test(list: &mut SkipList, size: u64, seed: u64, value: V) { let random = random::new(seed); let n = 0; @@ -492,6 +499,7 @@ module move_stl::skip_list { } #[test] + #[lint_allow(self_transfer)] fun test_insert() { let ctx = &mut tx_context::dummy(); let list = new_list_for_test(16, 2, 3000, 1234, 0, ctx); @@ -499,6 +507,7 @@ module move_stl::skip_list { } #[test] + #[lint_allow(self_transfer)] fun test_insert_bench() { let ctx = &mut tx_context::dummy(); let list = new(16, 2, 100000, ctx); @@ -513,6 +522,7 @@ module move_stl::skip_list { transfer::transfer(list, tx_context::sender(ctx)); } + #[allow(unused_field)] struct Item has drop, store { n: u64, score: u64, @@ -520,6 +530,7 @@ module move_stl::skip_list { } #[test] + #[lint_allow(self_transfer)] fun test_find() { let ctx = &mut tx_context::dummy(); let list = new_list_for_test(16, 2, 1000, 12345, 0, ctx); @@ -567,6 +578,7 @@ module move_stl::skip_list { } #[test] + #[lint_allow(self_transfer)] fun test_find_bench() { let ctx = &mut tx_context::dummy(); let list = new_list_for_test(16, 2, 1000, 12345, 0, ctx); @@ -585,6 +597,7 @@ module move_stl::skip_list { } #[test] + #[lint_allow(self_transfer)] fun test_find_next_bench() { let ctx = &mut tx_context::dummy(); let list = new_list_for_test(16, 2, 1000, 12345, 0, ctx); @@ -599,6 +612,7 @@ module move_stl::skip_list { } #[test] + #[lint_allow(self_transfer)] fun test_remove() { let ctx = &mut tx_context::dummy(); let list = new_list_for_test(16, 2, 1000, 5678, 0, ctx); @@ -633,6 +647,7 @@ module move_stl::skip_list { } #[test] + #[lint_allow(self_transfer)] fun test_find_in_empty_list() { let ctx = &mut tx_context::dummy(); let list = new(16, 2, 1234, ctx); diff --git a/sui/sources/skip_list_u128.move b/sui/sources/skip_list_u128.move new file mode 100644 index 0000000..51429ef --- /dev/null +++ b/sui/sources/skip_list_u128.move @@ -0,0 +1,640 @@ +module move_stl::skip_list_u128 { + use sui::object::{Self, UID}; + use sui::tx_context::TxContext; + use std::vector::{Self, push_back}; + use sui::table; + use move_stl::option_u128::{Self, OptionU128, none, some, is_none, is_some, swap_or_fill, is_some_and_lte}; + use move_stl::random::{Self, Random}; + + const ENodeAlreadyExist: u64 = 0; + const ENodeDoesNotExist: u64 = 1; + const ESkipListNotEmpty: u64 = 3; + + /// The skip list. + struct SkipList has key, store{ + /// The id of this skip list. + id: UID, + /// The skip list header of each level. i.e. the score of node. + head: vector, + /// The level0's tail of skip list. i.e. the score of node. + tail: OptionU128, + /// The current level of this skip list. + level: u64, + /// The max level of this skip list. + max_level: u64, + /// Basic probability of random of node indexer's level i.e. (list_p = 2, level2 = 1/2, level3 = 1/4). + list_p: u64, + + /// The random for generate ndoe's level + random: Random, + + /// The table for store node. + inner: table::Table> + } + + /// The node of skip list. + struct SkipListNode has store { + /// The score of node. + score: u128, + /// The next node score of node's each level. + nexts: vector, + /// The prev node score of node. + prev: OptionU128, + /// The data being stored + value: V, + } + + /// Create a new empty skip list. + public fun new(max_level: u64, list_p: u64, seed: u64, ctx: &mut TxContext): SkipList { + let list = SkipList { + id: object::new(ctx), + head: vector::empty(), + tail: none(), + level: 0, + max_level, + list_p, + random: random::new(seed), + inner: table::new(ctx) + }; + list + } + + /// Return the length of the skip list. + public fun length(list: &SkipList): u64 { + table::length(&list.inner) + } + + /// Returns true if the skip list is empty (if `length` returns `0`) + public fun is_empty(list: &SkipList): bool { + table::length(&list.inner) == 0 + } + + /// Return the head of the skip list. + public fun head(list: &SkipList): OptionU128 { + if (is_empty(list)) { + return none() + }; + *vector::borrow(&list.head, 0) + } + + /// Return the tail of the skip list. + public fun tail(list: &SkipList): OptionU128 { + list.tail + } + + /// Destroys an empty skip list + /// Aborts with `ETableNotEmpty` if the list still contains values + public fun destroy_empty(list: SkipList) { + let SkipList { + id, + head: _, + tail: _, + level: _, + max_level: _, + list_p: _, + random: _, + inner + } = list; + assert!(table::length(&inner) == 0, ESkipListNotEmpty); + table::destroy_empty(inner); + object::delete(id); + } + + /// Returns true if there is a value associated with the score `score` in skip list `table: &SkipList` + public fun contains(list: &SkipList, score: u128): bool { + table::contains(&list.inner, score) + } + + /// Acquire an immutable reference to the `score` element of the skip list `list`. + /// Aborts if element not exist. + public fun borrow(list: &SkipList, score: u128): &V { + let node = table::borrow(&list.inner, score); + &node.value + } + + /// Return a mutable reference to the `score` element in the skip list `list`. + /// Aborts if element is not exist. + public fun borrow_mut(list: &mut SkipList, score: u128): &mut V { + let node = table::borrow_mut(&mut list.inner, score); + &mut node.value + } + + /// Acquire an immutable reference to the `score` node of the skip list `list`. + /// Aborts if node not exist. + public fun borrow_node(list: &SkipList, score: u128): &SkipListNode { + table::borrow(&list.inner, score) + } + + /// Return a mutable reference to the `score` node in the skip list `list`. + /// Aborts if node is not exist. + public fun borrow_mut_node(list: &mut SkipList, score: u128): &mut SkipListNode { + table::borrow_mut(&mut list.inner, score) + } + + /// Return the metadata info of skip list. + public fun metadata(list: &SkipList): (vector, OptionU128, u64, u64, u64, u64) { + ( + list.head, + list.tail, + list.level, + list.max_level, + list.list_p, + table::length(&list.inner) + ) + } + + /// Return the next score of the node. + public fun next_score(node: &SkipListNode): OptionU128 { + *vector::borrow(&node.nexts, 0) + } + + /// Return the prev score of the node. + public fun prev_score(node: &SkipListNode): OptionU128 { + node.prev + } + + /// Return the immutable reference to the ndoe's value. + public fun borrow_value(node: &SkipListNode): &V { + &node.value + } + + /// Return the mutable reference to the ndoe's value. + public fun borrow_mut_value(node: &mut SkipListNode): &mut V { + &mut node.value + } + + /// Insert a score-value into skip list, abort if the score alread exist. + public fun insert(list: &mut SkipList, score: u128, v: V) { + assert!(!table::contains(&list.inner, score), ENodeAlreadyExist); + let (level, new_node) = create_node(list, score, v); + let (l, nexts, prev) = (list.level, &mut list.head, none()); + let opt_l0_next_score = none(); + while(l > 0) { + let opt_next_score = vector::borrow_mut(nexts, l - 1); + while (is_some_and_lte(opt_next_score, score)) { + let node = table::borrow_mut(&mut list.inner, option_u128::borrow(opt_next_score)); + prev = some(node.score); + nexts = &mut node.nexts; + opt_next_score = vector::borrow_mut(nexts, l - 1); + }; + if (level >= l) { + vector::push_back(&mut new_node.nexts, *opt_next_score); + if (l == 1) { + new_node.prev = prev; + if (is_some(opt_next_score)) { + opt_l0_next_score = *opt_next_score; + } else { + list.tail = some(score); + } + }; + swap_or_fill(opt_next_score, score); + }; + l = l - 1; + }; + vector::reverse(&mut new_node.nexts); + table::add(&mut list.inner, score, new_node); + if (is_some(&opt_l0_next_score)) { + let next_node = table::borrow_mut(&mut list.inner, option_u128::borrow(&opt_l0_next_score)); + next_node.prev = some(score); + }; + } + + /// Remove the score-value from skip list, abort if the score not exist in list. + public fun remove(list: &mut SkipList, score: u128): V { + assert!(table::contains(&list.inner, score), ENodeDoesNotExist); + let (l, nexts) = (list.level, &mut list.head); + let node = table::remove(&mut list.inner, score); + while (l > 0) { + let opt_next_score = vector::borrow_mut(nexts, l - 1); + while (is_some_and_lte(opt_next_score, score)) { + let next_score = option_u128::borrow(opt_next_score); + if (next_score == score) { + *opt_next_score = *vector::borrow(&node.nexts, l - 1); + } else { + let node = table::borrow_mut(&mut list.inner, next_score); + nexts = &mut node.nexts; + opt_next_score = vector::borrow_mut(nexts, l - 1); + } + }; + l = l - 1; + }; + + if (option_u128::borrow(&list.tail) == score) { + list.tail = node.prev; + }; + + let opt_l0_next_score = vector::borrow(&node.nexts, 0); + if (is_some(opt_l0_next_score)) { + let next_node = table::borrow_mut(&mut list.inner, option_u128::borrow(opt_l0_next_score)); + next_node.prev = node.prev; + }; + + drop_node(node) + } + + /// Return the next score. + public fun find_next(list: &SkipList, score: u128, include: bool): OptionU128 { + let opt_finded_score = find(list, score); + if (is_none(&opt_finded_score)) { + return opt_finded_score + }; + let finded_score = option_u128::borrow(&opt_finded_score); + if ((include && finded_score == score) || (finded_score > score)) { + return opt_finded_score + }; + let node = borrow_node(list, finded_score); + *vector::borrow(&node.nexts, 0) + } + + /// Return the prev socre. + public fun find_prev(list: &SkipList, score: u128, include: bool): OptionU128 { + let opt_finded_score = find(list, score); + if (is_none(&opt_finded_score)) { + return opt_finded_score + }; + let finded_score = option_u128::borrow(&opt_finded_score); + if ((include && finded_score == score) || (finded_score < score)) { + return opt_finded_score + }; + let node = borrow_node(list, finded_score); + node.prev + } + + /// Find the nearest score. 1. score, 2. prev, 3. next + fun find(list: &SkipList, score: u128): OptionU128 { + let (l, nexts,current_score) = (list.level, &list.head, none()); + while (l > 0) { + let opt_next_score = *vector::borrow(nexts, l - 1); + while(is_some_and_lte(&opt_next_score, score)) { + let next_score = option_u128::borrow(&opt_next_score); + if (next_score == score) { + return some(next_score) + } else { + let node = table::borrow(&list.inner, next_score); + current_score = opt_next_score; + nexts = &node.nexts; + opt_next_score = *vector::borrow(nexts, l - 1); + }; + }; + if (l == 1 && is_some(¤t_score)) { + return current_score + }; + l = l - 1; + }; + return *vector::borrow(&list.head, 0) + } + + fun rand_level(seed: u64, list: &SkipList): u64 { + let level = 1; + let mod = list.list_p; + while ((seed % mod) == 0) { + mod = mod * list.list_p; + level = level + 1; + if (level > list.level) { + if (level >= list.max_level) { + level = list.max_level; + break + } else { + level = list.level + 1; + break + } + } + }; + level + } + + /// Create a new skip list node + fun create_node(list: &mut SkipList, score: u128, value: V): (u64, SkipListNode) { + let rand = random::rand(&mut list.random); + let level = rand_level(rand, list); + + // Create a new level for skip list. + if (level > list.level) { + list.level = level; + push_back(&mut list.head, none()); + }; + + ( + level, + SkipListNode { + score, + nexts: vector::empty(), + prev: none(), + value + } + ) + } + + fun drop_node(node: SkipListNode): V { + let SkipListNode { + score: _, + nexts: _, + prev: _, + value, + } = node; + value + } + + // tests + // ============================================================================================ + #[test_only] + use sui::tx_context; + #[test_only] + use sui::transfer; + #[test_only] + use std::debug; + + #[test_only] + #[allow(unused_function)] + fun print_skip_list(list: &SkipList) { + debug::print(list); + if (length(list) == 0) { + return + }; + let next_score = vector::borrow(&list.head, 0); + while (is_some(next_score)) { + let node = table::borrow(&list.inner, option_u128::borrow(next_score)); + next_score = vector::borrow(&node.nexts, 0); + debug::print(node); + } + } + + #[test_only] + #[lint_allow(self_transfer)] + fun check_skip_list(list: &SkipList) { + if (list.level == 0) { + assert!(table::length(&list.inner) == 0, 0); + return + }; + + // Check level 0 + let ( + size, + opt_next_score, + tail, + prev, + current_score, + ) = ( + 0, + vector::borrow(&list.head, 0), + none(), + none(), + none() + ); + while (is_some(opt_next_score)) { + let next_score = option_u128::borrow(opt_next_score); + let next_node = table::borrow(&list.inner, next_score); + if (is_some(¤t_score)) { + assert!(next_score > option_u128::borrow(¤t_score), 0); + }; + assert!(next_node.score == next_score, 0); + if (is_none(&prev)) { + assert!(is_none(&next_node.prev), 0) + } else { + assert!(option_u128::borrow(&next_node.prev) == option_u128::borrow(&prev), 0); + }; + prev = some(next_node.score); + tail = some(next_node.score); + //current_score = next_node.score; + swap_or_fill(&mut current_score, next_node.score); + size = size + 1; + opt_next_score = vector::borrow(&next_node.nexts, 0); + }; + if (is_none(&tail)) { + assert!(is_none(&list.tail), 0); + } else { + assert!(option_u128::borrow(&list.tail) == option_u128::borrow(&tail), 0); + }; + assert!(size == table::length(&list.inner), 0); + + // Check indexer levels + let l = list.level - 1; + while (l > 0) { + let opt_next_l_score = vector::borrow(&list.head, l); + let opt_next_0_score = vector::borrow(&list.head, 0); + while(is_some(opt_next_0_score)) { + let next_0_score = option_u128::borrow(opt_next_0_score); + let node = table::borrow(&list.inner, next_0_score); + if (is_none(opt_next_l_score) || option_u128::borrow(opt_next_l_score) > node.score) { + assert!(vector::length(&node.nexts) <= l, 0); + } else { + if (vector::length(&node.nexts) > l) { + assert!(option_u128::borrow(opt_next_l_score) == node.score, 0); + opt_next_l_score = vector::borrow(&node.nexts, l); + } + }; + opt_next_0_score = vector::borrow(&node.nexts, 0); + }; + l = l - 1; + }; + } + + #[test_only] + #[lint_allow(self_transfer)] + fun get_all_socres(list: &SkipList): vector { + let (opt_next_score,scores ) = (vector::borrow(&list.head, 0), vector::empty()); + while (is_some(opt_next_score)) { + let next_score = option_u128::borrow(opt_next_score); + let next_node = table::borrow(&list.inner, next_score); + vector::push_back(&mut scores, next_node.score); + opt_next_score = vector::borrow(&next_node.nexts, 0); + }; + scores + } + + #[test] + #[lint_allow(self_transfer)] + fun test_new() { + let ctx = &mut tx_context::dummy(); + let skip_list = new(16, 2, 12345, ctx); + check_skip_list(&skip_list); + transfer::transfer(skip_list, tx_context::sender(ctx)); + } + + #[test] + #[lint_allow(self_transfer)] + fun test_create_node() { + let ctx = &mut tx_context::dummy(); + let skip_list = new(16, 2, 12345, ctx); + let n = 0; + while (n < 10) { + let (_, node) = create_node(&mut skip_list, n, 0); + let SkipListNode{score:_, value:_, nexts:_, prev:_} = node; + n = n + 1; + }; + check_skip_list(&skip_list); + transfer::transfer(skip_list, tx_context::sender(ctx)); + } + + #[test_only] + fun add_node_for_test(list: &mut SkipList, size: u64, seed: u64, value: V) { + let random = random::new(seed); + let n = 0; + while (n < size) { + let score = (random::rand_n(&mut random, 1000000) as u128); + if (contains(list, score)) { + continue + }; + insert(list, score, value); + n = n + 1; + }; + check_skip_list(list); + } + + #[test_only] + fun new_list_for_test( + max_leveL: u64, list_p: u64, size: u64, seed: u64, value: V, ctx: &mut TxContext + ): SkipList { + let list = new(max_leveL, list_p, seed, ctx); + add_node_for_test(&mut list, size, seed, value); + list + } + + #[test] + #[lint_allow(self_transfer)] + fun test_insert() { + let ctx = &mut tx_context::dummy(); + let list = new_list_for_test(16, 2, 3000, 1234, 0, ctx); + transfer::transfer(list, tx_context::sender(ctx)); + } + + #[test] + #[lint_allow(self_transfer)] + fun test_insert_bench() { + let ctx = &mut tx_context::dummy(); + let list = new(16, 2, 12345, ctx); + let n = 0; + while (n < 5001) { + insert(&mut list, 0 + n, 0); + insert(&mut list, 1000000 - n, 0); + insert(&mut list, 100000 - n, 0); + n = n + 1; + }; + // debug::print(&list.level); + transfer::transfer(list, tx_context::sender(ctx)); + } + + #[allow(unused_field)] + struct Item has drop, store { + n: u64, + score: u64, + finded: OptionU128 + } + + #[test] + #[lint_allow(self_transfer)] + fun test_find() { + let ctx = &mut tx_context::dummy(); + let list = new_list_for_test(16, 2, 1000, 12345, 0, ctx); + let scores = get_all_socres(&list); + + let length = vector::length(&scores); + let n = length; + while ( n > 0) { + let score = *vector::borrow(&scores, n - 1); + let finded = find_prev(&list, score, true); + assert!((is_some(&finded) && (option_u128::borrow(&finded) == score)), 0); + let finded = find_prev(&list, score + 1, true); + assert!( + (is_some(&finded) && (option_u128::borrow(&finded) == score)) || + (is_some(&finded) && (option_u128::borrow(&finded) == score + 1)), + 0 + ); + + let finded = find_prev(&list, score, false); + if (n >= 2) { + assert!((is_some(&finded) && (option_u128::borrow(&finded) == *vector::borrow(&scores, n - 2))), 0); + } else { + assert!(is_none(&finded), 0); + }; + + let finded = find_next(&list, score, true); + assert!((is_some(&finded) && (option_u128::borrow(&finded) == score)), 0); + + let finded = find_next(&list, score - 1, true); + assert!( + (is_some(&finded) && (option_u128::borrow(&finded) == score)) || + (is_some(&finded) && (option_u128::borrow(&finded) == (score - 1))), + 0 + ); + + let finded = find_next(&list, score, false); + if (n < length) { + assert!((is_some(&finded) && (option_u128::borrow(&finded) == *vector::borrow(&scores, n))), 0); + } else { + assert!(is_none(&finded), 0); + }; + n = n - 1; + }; + transfer::transfer(list, tx_context::sender(ctx)); + } + + #[test] + #[lint_allow(self_transfer)] + fun test_find_bench() { + let ctx = &mut tx_context::dummy(); + let list = new_list_for_test(16, 2, 1000, 12345, 0, ctx); + let random = random::new(12345); + let n = 0; + while (n < 100) { + let score = (random::rand_n(&mut random, 1000000) as u128); + if ((n % 3) == 0) { + score = score + 1; + }; + find(&list, score); + _ = score; + n = n + 1; + }; + transfer::transfer(list, tx_context::sender(ctx)); + } + + #[test] + #[lint_allow(self_transfer)] + fun test_find_next_bench() { + let ctx = &mut tx_context::dummy(); + let list = new_list_for_test(16, 2, 1000, 12345, 0, ctx); + let n = 0; + let finded = find_next(&list, 99999, true); + while (n < 1 && is_some(&finded)) { + let node = borrow_node(&list, option_u128::borrow(&finded)); + finded = next_score(node); + n = n + 1; + }; + transfer::transfer(list, tx_context::sender(ctx)); + } + + #[test] + #[lint_allow(self_transfer)] + fun test_remove() { + let ctx = &mut tx_context::dummy(); + let list = new_list_for_test(16, 2, 1000, 5678, 0, ctx); + let scores = get_all_socres(&list); + let (n, length) = (0, vector::length(&scores)); + let start = length / 2; + while(n <= start) { + let s1 = start - n; + let s2 = start + n; + if (s1 >= 0) { + remove(&mut list, *vector::borrow(&scores, s1)); + }; + if (s2 != s1 && s2 < length ) { + remove(&mut list, *vector::borrow(&scores, s2)); + }; + n = n + 1; + }; + check_skip_list(&list); + + add_node_for_test(&mut list, 2000, 7890, 0); + let scores = get_all_socres(&list); + let (n, length) = (0, vector::length(&scores)); + let skip = 0; + while(n < length) { + remove(&mut list, *vector::borrow(&scores, n)); + skip = skip + 1; + n = n + skip; + }; + check_skip_list(&list); + + transfer::transfer(list, tx_context::sender(ctx)); + } +} From be0486062ab685cfe000d8ad5181eae1aa9c9c78 Mon Sep 17 00:00:00 2001 From: murphy0612 Date: Sun, 31 Dec 2023 08:29:01 +0000 Subject: [PATCH 2/2] Publish on mainnet --- sui/Move.lock | 2 +- sui/Move.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sui/Move.lock b/sui/Move.lock index f03f4ef..3474206 100644 --- a/sui/Move.lock +++ b/sui/Move.lock @@ -2,7 +2,7 @@ [move] version = 0 -manifest_digest = "A3A8D0CE24452F0F6AB1F7659366EC8994A4A6D8F29C331B04E88C1983483556" +manifest_digest = "3187E6E23D81B69A26EFE7BA7A92EE008F2F3217F08B987449AAE473BCA93D78" deps_digest = "F8BBB0CCB2491CA29A3DF03D6F92277A4F3574266507ACD77214D37ECA3F3082" dependencies = [ diff --git a/sui/Move.toml b/sui/Move.toml index bb1cc31..0d0c9b5 100644 --- a/sui/Move.toml +++ b/sui/Move.toml @@ -2,8 +2,8 @@ # ------------------------ [package] name = "MoveSTL" -version = "1.1.0" -published-at = "0xfacdeb69fc1354887ab4be6f8bd58b70a2c139ce85eb3cbc18b13013ff75ce73" +version = "1.2.0" +published-at = "0x7118b0382949f8321e995203c59eb60f0d48657d74234946d32b2bf7126ec80d" [dependencies] Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "mainnet-v1.15.1" }