Skip to content

Commit

Permalink
[AptosFramework] implement IterableTable
Browse files Browse the repository at this point in the history
  • Loading branch information
zekun000 authored and aptos-bot committed May 5, 2022
1 parent 0fdfdcd commit d1443a8
Show file tree
Hide file tree
Showing 17 changed files with 7,257 additions and 2,649 deletions.
734 changes: 734 additions & 0 deletions api/goldens/aptos_api__tests__accounts_test__test_account_modules.json

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
"type": "block_metadata_transaction",
"version": "1",
"hash": "0xa7ec7246c510563a87141e5936b16a02d4acff7cb29b9cdbaf5bcd7772bd1dfc",
"state_root_hash": "0x43ce6993c20e8fae90e19b0b64f57a6cb60a9f5e7fd669775491835bf31a055a",
"state_root_hash": "0x12fc3b94ad3254f5f9ac4b0040247830939dd8e744f89b11d297db64f1d2eaac",
"event_root_hash": "0x8f0766912895669a4ab13dc38d57a4975aa4e0676511146ff18b656b09775fe2",
"gas_used": "0",
"success": true,
"vm_status": "Executed successfully",
"accumulator_root_hash": "0xaf8ad3a9923acd80bc50ebc70de79b5236d0c5d1dbc660987412aaba59b605ab",
"accumulator_root_hash": "0x4d0f4e03de2dfc02d0086ba806903e3a291a88e45968ad98bce5f1d92853e118",
"changes": [
{
"type": "write_resource",
Expand Down Expand Up @@ -56,12 +56,12 @@
"type": "user_transaction",
"version": "2",
"hash": "0xab573777842a7e334ebe7c269717baa8a7bc4bdf28cdc2d288099ef267f09ccd",
"state_root_hash": "0xa9b89c38bc55aeae25c33529f0d534b4e77a26ea089243d93efd439353dd6e44",
"state_root_hash": "0xf3d812fff4e82f6fc62956c31c95ce761112e75beef5a9d4ccf6910e8a4d3f7b",
"event_root_hash": "0x414343554d554c41544f525f504c414345484f4c4445525f4841534800000000",
"gas_used": "92",
"success": true,
"vm_status": "Executed successfully",
"accumulator_root_hash": "0xc3682e4f24da7e5ca404661981810208a28968f9be3f4f89e678a9a4d60d40be",
"accumulator_root_hash": "0x099497d871bdf89ce237b5d293940704edc2b6249a3b70ea09a160b00ed6fb78",
"changes": [
{
"type": "write_resource",
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
"type": "user_transaction",
"version": "2",
"hash": "0x92227dd758094fca1efa07a1316d3fede8dd9ebd0eff8f90ed55d288787de528",
"state_root_hash": "0x9dd9b394e722becec025904a320b60376b2e579ad4bc50e259fdace259e16ffd",
"state_root_hash": "0xc8f134b5401270b473ed503db7724ec3326baff78f8c71f5ccce39451bcb9635",
"event_root_hash": "0x414343554d554c41544f525f504c414345484f4c4445525f4841534800000000",
"gas_used": "1",
"success": false,
"vm_status": "Transaction Executed and Committed with Error MALFORMED",
"accumulator_root_hash": "0x992a867d12af9c17262ce2913b8b707dc6363598c71dcbf8210bac984a723426",
"accumulator_root_hash": "0x83365487d9ebd71f8187aa263a8f89673d8c7c7f35b4d44edc51b618e3e187e2",
"changes": [
{
"type": "write_resource",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
"type": "user_transaction",
"version": "2",
"hash": "0x247ddbc48e7a7ae25419fcdba2d3ee47c822fa86817bd63a071bc46e1021ce8b",
"state_root_hash": "0x9dd9b394e722becec025904a320b60376b2e579ad4bc50e259fdace259e16ffd",
"state_root_hash": "0xc8f134b5401270b473ed503db7724ec3326baff78f8c71f5ccce39451bcb9635",
"event_root_hash": "0x414343554d554c41544f525f504c414345484f4c4445525f4841534800000000",
"gas_used": "1",
"success": false,
"vm_status": "Transaction Executed and Committed with Error LINKER_ERROR",
"accumulator_root_hash": "0xa2935f8c12a7b8664717784232caf1ae29f172f7e7ee1cad522a725380ff7b37",
"accumulator_root_hash": "0x7074319879ab2797cc11a0b0baf8aba5ba7b44a206a0a63820a4b9390556f032",
"changes": [
{
"type": "write_resource",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
"type": "user_transaction",
"version": "2",
"hash": "0x02aa80c427a672ff050f2feccfdd8b26ccd0e71a6933aa159d6910d38695eb22",
"state_root_hash": "0x9dd9b394e722becec025904a320b60376b2e579ad4bc50e259fdace259e16ffd",
"state_root_hash": "0xc8f134b5401270b473ed503db7724ec3326baff78f8c71f5ccce39451bcb9635",
"event_root_hash": "0x414343554d554c41544f525f504c414345484f4c4445525f4841534800000000",
"gas_used": "1",
"success": false,
"vm_status": "Transaction Executed and Committed with Error FAILED_TO_DESERIALIZE_ARGUMENT",
"accumulator_root_hash": "0xa822c2214bfeeca6045e36ad58da08ca0b0e945783c9c98985222dd2860f60ac",
"accumulator_root_hash": "0xd4207362eabcdda98888203505c1e41468964f2641964fa490f1d7dd0af514c6",
"changes": [
{
"type": "write_resource",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
"type": "user_transaction",
"version": "2",
"hash": "0x482239a738fb8f7c9cf0f96a6e20bb75d69ef328cacc6b52ef5f74d28fd27ce3",
"state_root_hash": "0x9dd9b394e722becec025904a320b60376b2e579ad4bc50e259fdace259e16ffd",
"state_root_hash": "0xc8f134b5401270b473ed503db7724ec3326baff78f8c71f5ccce39451bcb9635",
"event_root_hash": "0x414343554d554c41544f525f504c414345484f4c4445525f4841534800000000",
"gas_used": "1",
"success": false,
"vm_status": "Transaction Executed and Committed with Error LINKER_ERROR",
"accumulator_root_hash": "0x8112192fab2cf3debe9e85bc3d31051660262c9a2ae8d8a0ac4c6d22cec0878c",
"accumulator_root_hash": "0x73580b0bdb79be5abd26a33e0e110e289bf330c74eec9cc0e2e3b64c1049ce21",
"changes": [
{
"type": "write_resource",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
"type": "user_transaction",
"version": "2",
"hash": "0xb0fe2740ac760ccdfd8dd7cd33a95e8da3a40daeefb0f9c0ebb963b9b07c530a",
"state_root_hash": "0x9dd9b394e722becec025904a320b60376b2e579ad4bc50e259fdace259e16ffd",
"state_root_hash": "0xc8f134b5401270b473ed503db7724ec3326baff78f8c71f5ccce39451bcb9635",
"event_root_hash": "0x414343554d554c41544f525f504c414345484f4c4445525f4841534800000000",
"gas_used": "1",
"success": false,
"vm_status": "Transaction Executed and Committed with Error FUNCTION_RESOLUTION_FAILURE",
"accumulator_root_hash": "0x891c41e6783e956d5f88373c0f9becc8e4b3dfae16b9ab65ae150e5caaa8cc35",
"accumulator_root_hash": "0x2727568075285e1fc60fba087fb1c4e2cd78a9b2cd9765a0546f693178fc76e2",
"changes": [
{
"type": "write_resource",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
"type": "user_transaction",
"version": "2",
"hash": "0xcbdb69429665e6815b49119ed46e86cb059151be73c762f0daada3b56cee6d22",
"state_root_hash": "0x9dd9b394e722becec025904a320b60376b2e579ad4bc50e259fdace259e16ffd",
"state_root_hash": "0xc8f134b5401270b473ed503db7724ec3326baff78f8c71f5ccce39451bcb9635",
"event_root_hash": "0x414343554d554c41544f525f504c414345484f4c4445525f4841534800000000",
"gas_used": "1",
"success": false,
"vm_status": "Transaction Executed and Committed with Error CODE_DESERIALIZATION_ERROR",
"accumulator_root_hash": "0xdd9afa79a8f64aa39a519f53d65f69bc29a1700809b4a124d7dfe54a92941a68",
"accumulator_root_hash": "0xc1f30449cb990b30c1a14404bdf1f6a860bf7e761bcace21b896ae2041ad58b2",
"changes": [
{
"type": "write_resource",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
"type": "user_transaction",
"version": "2",
"hash": "0x84f76218c265cde5a994b42621613ac6c2496d383c3ed1e2a525d455f49411ec",
"state_root_hash": "0x9dd9b394e722becec025904a320b60376b2e579ad4bc50e259fdace259e16ffd",
"state_root_hash": "0xc8f134b5401270b473ed503db7724ec3326baff78f8c71f5ccce39451bcb9635",
"event_root_hash": "0x414343554d554c41544f525f504c414345484f4c4445525f4841534800000000",
"gas_used": "1",
"success": false,
"vm_status": "Transaction Executed and Committed with Error NUMBER_OF_ARGUMENTS_MISMATCH",
"accumulator_root_hash": "0x7041a2faa8fe7403cc1e12a42e6018e183ecfca1dfa024b52bc7fc14d452134c",
"accumulator_root_hash": "0x3a2fdbf1e39fec4d6f5ca3760b56e6d6912e303542148bd13c716941267c8d2c",
"changes": [
{
"type": "write_resource",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
"type": "user_transaction",
"version": "4",
"hash": "0xb60f7bb176918849ad6f73c01695881dd1c1aa074d766174a5a6e43e7b8c557c",
"state_root_hash": "0x8ee95abc981028781b8a69851c8d5080999d99e9de99bf25d8205683ba7faaca",
"state_root_hash": "0x989b8988cba89d8576c4dbf06ad3b7eb718b2e5ecb0c94219f0746b2fbcab92d",
"event_root_hash": "0x414343554d554c41544f525f504c414345484f4c4445525f4841534800000000",
"gas_used": "21",
"success": false,
"vm_status": "Move abort by LIMIT_EXCEEDED - EINSUFFICIENT_BALANCE\n A limit on an amount, e.g. a currency, is exceeded. Example: withdrawal of money after account limits window\n is exhausted.\n Error codes",
"accumulator_root_hash": "0x0e90265a87f415c2c975d21d549ab0526d087f79ed8985e441d6436372ef5fe8",
"accumulator_root_hash": "0x67d596953ae7f6b8db109af1a317d98e92709d6a154969ee3d5253505a5b5991",
"changes": [
{
"type": "write_resource",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,4 +204,4 @@ module AptosFramework::BigVector {
};
destroy_empty(v);
}
}
}
184 changes: 184 additions & 0 deletions aptos-move/framework/aptos-framework/sources/IterableTable.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
module AptosFramework::IterableTable {
use Std::Option::{Self, Option};
use AptosFramework::Table::{Self, Table};

/// The iterable wrapper around value, points to previous and next key if any.
struct IterableValue<K: copy + store + drop, V: store> has store {
val: V,
prev: Option<K>,
next: Option<K>,
}

/// An iterable table implementation based on double linked list.
struct IterableTable<K: copy + store + drop, V: store> has store {
inner: Table<K, IterableValue<K, V>>,
head: Option<K>,
tail: Option<K>,
}

/// Regular table API.
/// Create an empty table.
public fun new<K: copy + store + drop, V: store>(): IterableTable<K, V> {
IterableTable {
inner: Table::new(),
head: Option::none(),
tail: Option::none(),
}
}

/// Destroy a table. The table must be empty to succeed.
public fun destroy_empty<K: copy + store + drop, V: store>(table: IterableTable<K, V>) {
assert!(empty(&table), 0);
assert!(Option::is_none(&table.head), 0);
assert!(Option::is_none(&table.tail), 0);
let IterableTable {inner, head: _, tail: _} = table;
Table::destroy_empty(inner);
}

/// Add a new entry to the table. Aborts if an entry for this
/// key already exists.
public fun add<K: copy + store + drop, V: store>(table: &mut IterableTable<K, V>, key: &K, val: V) {
let wrapped_value = IterableValue {
val,
prev: table.tail,
next: Option::none(),
};
Table::add(&mut table.inner, key, wrapped_value);
if (Option::is_some(&table.tail)) {
let k = Option::borrow(&table.tail);
Table::borrow_mut(&mut table.inner, k).next = Option::some(*key);
} else {
table.head = Option::some(*key);
};
table.tail = Option::some(*key);
}

/// Remove from `table` and return the value which `key` maps to.
/// Aborts if there is no entry for `key`.
public fun remove<K: copy + store + drop, V: store>(table: &mut IterableTable<K, V>, key: &K): V {
let (val, _, _) = remove_iter(table, key);
val
}

/// Acquire an immutable reference to the value which `key` maps to.
/// Aborts if there is no entry for `key`.
public fun borrow<K: copy + store + drop, V: store>(table: &IterableTable<K, V>, key: &K): &V {
&Table::borrow(&table.inner, key).val
}

/// Acquire a mutable reference to the value which `key` maps to.
/// Aborts if there is no entry for `key`.
public fun borrow_mut<K: copy + store + drop, V: store>(table: &mut IterableTable<K, V>, key: &K): &mut V {
&mut Table::borrow_mut(&mut table.inner, key).val
}

/// Returns the length of the table, i.e. the number of entries.
public fun length<K: copy + store + drop, V: store>(table: &IterableTable<K, V>): u64 {
Table::length(&table.inner)
}

/// Returns true if this table is empty.
public fun empty<K: copy + store + drop, V: store>(table: &IterableTable<K, V>): bool {
Table::empty(&table.inner)
}

/// Returns true iff `table` contains an entry for `key`.
public fun contains<K: copy + store + drop, V: store>(table: &IterableTable<K, V>, key: &K): bool {
Table::contains(&table.inner, key)
}

/// Iterable API.
/// Returns the key of the head for iteration.
public fun head_key<K: copy + store + drop, V: store>(table: &IterableTable<K, V>): Option<K> {
table.head
}

/// Returns the key of the tail for iteration.
public fun tail_key<K: copy + store + drop, V: store>(table: &IterableTable<K, V>): Option<K> {
table.tail
}

/// Acquire an immutable reference to the IterableValue which `key` maps to.
/// Aborts if there is no entry for `key`.
public fun borrow_iter<K: copy + store + drop, V: store>(table: &IterableTable<K, V>, key: &K): (&V, Option<K>, Option<K>) {
let v = Table::borrow(&table.inner, key);
(&v.val, v.prev, v.next)
}

/// Acquire an immutable reference to the value and previous/next key which `key` maps to
/// Aborts if there is no entry for `key`.
public fun borrow_iter_mut<K: copy + store + drop, V: store>(table: &mut IterableTable<K, V>, key: &K): (&mut V, Option<K>, Option<K>) {
let v = Table::borrow_mut(&mut table.inner, key);
(&mut v.val, v.prev, v.next)
}

/// Remove from `table` and return the value and previous/next key which `key` maps to.
/// Aborts if there is no entry for `key`.
public fun remove_iter<K: copy + store + drop, V: store>(table: &mut IterableTable<K, V>, key: &K): (V, Option<K>, Option<K>) {
let val = Table::remove(&mut table.inner, key);
if (Option::contains(&table.tail, key)) {
table.tail = val.prev;
};
if (Option::contains(&table.head, key)) {
table.head = val.next;
};
if (Option::is_some(&val.prev)) {
let key = Option::borrow(&val.prev);
Table::borrow_mut(&mut table.inner, key).next = val.next;
};
if (Option::is_some(&val.next)) {
let key = Option::borrow(&val.next);
Table::borrow_mut(&mut table.inner, key).prev = val.prev;
};
let IterableValue {val, prev, next} = val;
(val, prev, next)
}

/// Remove all items from v2 and append to v1.
public fun append<K: copy + store + drop, V: store>(v1: &mut IterableTable<K, V>, v2: &mut IterableTable<K, V>) {
let key = head_key(v2);
while (Option::is_some(&key)) {
let (val, _, next) = remove_iter(v2, Option::borrow(&key));
add(v1, Option::borrow(&key), val);
key = next;
};
}

#[test]
fun iterable_table_test() {
let table = new();
let i = 0;
while (i < 100) {
add(&mut table, &i, i);
i = i + 1;
};
assert!(length(&table) == 100, 0);
i = 0;
while (i < 100) {
assert!(remove(&mut table, &i) == i, 0);
i = i + 2;
};
assert!(!empty(&table), 0);
let key = head_key(&table);
i = 1;
while (Option::is_some(&key)) {
let (val, _, next) = borrow_iter(&table, Option::borrow(&key));
assert!(*val == i, 0);
key = next;
i = i + 2;
};
assert!(i == 101, 0);
let table2 = new();
append(&mut table2, &mut table);
destroy_empty(table);
let key = tail_key(&table2);
while (Option::is_some(&key)) {
let (val, prev, _) = remove_iter(&mut table2, Option::borrow(&key));
assert!(val == *Option::borrow(&key), 0);
key = prev;
};
destroy_empty(table2);
}
}

0 comments on commit d1443a8

Please sign in to comment.