Module 0x1::smart_table
A smart table implementation based on linear hashing. (https://en.wikipedia.org/wiki/Linear_hashing) Compare to Table, it uses less storage slots but has higher chance of collision, a trade-off between space and time. Compare to other dynamic hashing implementation, linear hashing splits one bucket a time instead of doubling buckets when expanding to avoid unexpected gas cost. SmartTable uses faster hash function SipHash instead of cryptographically secure hash functions like sha3-256 since it tolerates collisions.
DEPRECATED: since it’s implementation is inneficient, it
has been deprecated in favor of big_ordered_map.move.
- Struct
Entry - Struct
SmartTable - Constants
- Function
new - Function
new_with_config - Function
destroy_empty - Function
destroy - Function
clear - Function
add - Function
add_all - Function
unzip_entries - Function
to_simple_map - Function
keys - Function
keys_paginated - Function
split_one_bucket - Function
bucket_index - Function
borrow - Function
borrow_with_default - Function
borrow_mut - Function
borrow_mut_with_default - Function
contains - Function
remove - Function
upsert - Function
length - Function
load_factor - Function
update_split_load_threshold - Function
update_target_bucket_size - Function
for_each_ref - Function
for_each_mut - Function
map_ref - Function
any - Function
borrow_kv - Function
borrow_kv_mut - Function
num_buckets - Function
borrow_buckets - Function
borrow_buckets_mut - Specification
- Struct
SmartTable - Function
new_with_config - Function
destroy - Function
clear - Function
add_all - Function
to_simple_map - Function
keys - Function
keys_paginated - Function
split_one_bucket - Function
bucket_index - Function
load_factor - Function
update_split_load_threshold - Function
update_target_bucket_size - Function
borrow_kv - Function
borrow_kv_mut - Function
num_buckets - Function
borrow_buckets - Function
borrow_buckets_mut
- Struct
use 0x1::aptos_hash;
use 0x1::error;
use 0x1::math64;
use 0x1::option;
use 0x1::simple_map;
use 0x1::table_with_length;
use 0x1::type_info;
use 0x1::vector;
Struct Entry
SmartTable entry contains both the key and value.
struct Entry<K, V> has copy, drop, store
Fields
-
hash: u64 -
key: K -
value: V
Struct SmartTable
struct SmartTable<K, V> has store
Fields
-
buckets: table_with_length::TableWithLength<u64, vector<smart_table::Entry<K, V>>> -
num_buckets: u64 -
level: u8 -
size: u64 -
split_load_threshold: u8 -
target_bucket_size: u64
Constants
Cannot destroy non-empty hashmap
const ENOT_EMPTY: u64 = 3;
Key not found in the smart table
const ENOT_FOUND: u64 = 1;
Key already exists
const EALREADY_EXIST: u64 = 4;
Invalid target bucket size.
const EEXCEED_MAX_BUCKET_SIZE: u64 = 7;
Invalid bucket index.
const EINVALID_BUCKET_INDEX: u64 = 8;
Invalid load threshold percent to trigger split.
const EINVALID_LOAD_THRESHOLD_PERCENT: u64 = 5;
Invalid target bucket size.
const EINVALID_TARGET_BUCKET_SIZE: u64 = 6;
Invalid vector index within a bucket.
const EINVALID_VECTOR_INDEX: u64 = 9;
Smart table capacity must be larger than 0
const EZERO_CAPACITY: u64 = 2;
Function new
Create an empty SmartTable with default configurations.
public fun new<K: copy, drop, store, V: store>(): smart_table::SmartTable<K, V>
Implementation
public fun new<K: copy + drop + store, V: store>(): SmartTable<K, V> {
new_with_config<K, V>(0, 0, 0)
}
Function new_with_config
Create an empty SmartTable with customized configurations.
num_initial_buckets: The number of buckets on initialization. 0 means using default value.
split_load_threshold: The percent number which once reached, split will be triggered. 0 means using default
value.
target_bucket_size: The target number of entries per bucket, though not guaranteed. 0 means not set and will
dynamically assgined by the contract code.
public fun new_with_config<K: copy, drop, store, V: store>(num_initial_buckets: u64, split_load_threshold: u8, target_bucket_size: u64): smart_table::SmartTable<K, V>
Implementation
public fun new_with_config<K: copy + drop + store, V: store>(
num_initial_buckets: u64,
split_load_threshold: u8,
target_bucket_size: u64
): SmartTable<K, V> {
assert!(split_load_threshold <= 100, error::invalid_argument(EINVALID_LOAD_THRESHOLD_PERCENT));
let buckets = table_with_length::new();
buckets.add(0, vector::empty());
let table = SmartTable {
buckets,
num_buckets: 1,
level: 0,
size: 0,
// The default split load threshold is 75%.
split_load_threshold: if (split_load_threshold == 0) { 75 } else { split_load_threshold },
target_bucket_size,
};
// The default number of initial buckets is 2.
if (num_initial_buckets == 0) {
num_initial_buckets = 2;
};
while (num_initial_buckets > 1) {
num_initial_buckets -= 1;
table.split_one_bucket();
};
table
}
Function destroy_empty
Destroy empty table. Aborts if it’s not empty.
public fun destroy_empty<K, V>(self: smart_table::SmartTable<K, V>)
Implementation
public fun destroy_empty<K, V>(self: SmartTable<K, V>) {
assert!(self.size == 0, error::invalid_argument(ENOT_EMPTY));
for (i in 0..self.num_buckets) {
self.buckets.remove(i).destroy_empty();
};
let SmartTable { buckets, num_buckets: _, level: _, size: _, split_load_threshold: _, target_bucket_size: _ } = self;
buckets.destroy_empty();
}
Function destroy
Destroy a table completely when V has drop.
public fun destroy<K: drop, V: drop>(self: smart_table::SmartTable<K, V>)
Implementation
public fun destroy<K: drop, V: drop>(self: SmartTable<K, V>) {
self.clear();
self.destroy_empty();
}
Function clear
Clear a table completely when T has drop.
public fun clear<K: drop, V: drop>(self: &mut smart_table::SmartTable<K, V>)
Implementation
public fun clear<K: drop, V: drop>(self: &mut SmartTable<K, V>) {
*self.buckets.borrow_mut(0) = vector::empty();
for (i in 1..self.num_buckets) {
self.buckets.remove(i);
};
self.num_buckets = 1;
self.level = 0;
self.size = 0;
}
Function add
Add (key, value) pair in the hash map, it may grow one bucket if current load factor exceeds the threshold.
Note it may not split the actual overflowed bucket. Instead, it was determined by num_buckets and level.
For standard linear hash algorithm, it is stored as a variable but num_buckets here could be leveraged.
Abort if key already exists.
Note: This method may occasionally cost much more gas when triggering bucket split.
public fun add<K, V>(self: &mut smart_table::SmartTable<K, V>, key: K, value: V)
Implementation
public fun add<K, V>(self: &mut SmartTable<K, V>, key: K, value: V) {
let hash = sip_hash_from_value(&key);
let index = bucket_index(self.level, self.num_buckets, hash);
let bucket = self.buckets.borrow_mut(index);
// We set a per-bucket limit here with a upper bound (10000) that nobody should normally reach.
assert!(bucket.length() <= 10000, error::permission_denied(EEXCEED_MAX_BUCKET_SIZE));
assert!(bucket.all(| entry | {
let e: &Entry<K, V> = entry;
&e.key != &key
}), error::invalid_argument(EALREADY_EXIST));
let e = Entry { hash, key, value };
if (self.target_bucket_size == 0) {
let estimated_entry_size = max(size_of_val(&e), 1);
self.target_bucket_size = max(1024 /* free_write_quota */ / estimated_entry_size, 1);
};
bucket.push_back(e);
self.size += 1;
if (self.load_factor() >= (self.split_load_threshold as u64)) {
self.split_one_bucket();
}
}
Function add_all
Add multiple key/value pairs to the smart table. The keys must not already exist.
public fun add_all<K, V>(self: &mut smart_table::SmartTable<K, V>, keys: vector<K>, values: vector<V>)
Implementation
public fun add_all<K, V>(self: &mut SmartTable<K, V>, keys: vector<K>, values: vector<V>) {
keys.zip(values, |key, value| { self.add(key, value); });
}
Function unzip_entries
fun unzip_entries<K: copy, V: copy>(entries: &vector<smart_table::Entry<K, V>>): (vector<K>, vector<V>)
Implementation
inline fun unzip_entries<K: copy, V: copy>(entries: &vector<Entry<K, V>>): (vector<K>, vector<V>) {
let keys = vector[];
let values = vector[];
entries.for_each_ref(|e|{
let entry: &Entry<K, V> = e;
keys.push_back(entry.key);
values.push_back(entry.value);
});
(keys, values)
}
Function to_simple_map
Convert a smart table to a simple_map, which is supposed to be called mostly by view functions to get an atomic view of the whole table. Disclaimer: This function may be costly as the smart table may be huge in size. Use it at your own discretion.
public fun to_simple_map<K: copy, drop, store, V: copy, store>(self: &smart_table::SmartTable<K, V>): simple_map::SimpleMap<K, V>
Implementation
public fun to_simple_map<K: store + copy + drop, V: store + copy>(
self: &SmartTable<K, V>,
): SimpleMap<K, V> {
let res = simple_map::new<K, V>();
for (i in 0..self.num_buckets) {
let (keys, values) = unzip_entries(self.buckets.borrow(i));
res.add_all(keys, values);
};
res
}
Function keys
Get all keys in a smart table.
For a large enough smart table this function will fail due to execution gas limits, and
keys_paginated should be used instead.
public fun keys<K: copy, drop, store, V: copy, store>(self: &smart_table::SmartTable<K, V>): vector<K>
Implementation
public fun keys<K: store + copy + drop, V: store + copy>(
self: &SmartTable<K, V>
): vector<K> {
let (keys, _, _) = self.keys_paginated(0, 0, self.length());
keys
}
Function keys_paginated
Get keys from a smart table, paginated.
This function can be used to paginate all keys in a large smart table outside of runtime,
e.g. through chained view function calls. The maximum num_keys_to_get before hitting gas
limits depends on the data types in the smart table.
When starting pagination, pass starting_bucket_index = starting_vector_index = 0.
The function will then return a vector of keys, an optional bucket index, and an optional
vector index. The unpacked return indices can then be used as inputs to another pagination
call, which will return a vector of more keys. This process can be repeated until the
returned bucket index and vector index value options are both none, which means that
pagination is complete. For an example, see test_keys().
public fun keys_paginated<K: copy, drop, store, V: copy, store>(self: &smart_table::SmartTable<K, V>, starting_bucket_index: u64, starting_vector_index: u64, num_keys_to_get: u64): (vector<K>, option::Option<u64>, option::Option<u64>)
Implementation
public fun keys_paginated<K: store + copy + drop, V: store + copy>(
self: &SmartTable<K, V>,
starting_bucket_index: u64,
starting_vector_index: u64,
num_keys_to_get: u64,
): (
vector<K>,
Option<u64>,
Option<u64>,
) {
let num_buckets = self.num_buckets;
let buckets_ref = &self.buckets;
assert!(starting_bucket_index < num_buckets, EINVALID_BUCKET_INDEX);
let bucket_ref = buckets_ref.borrow(starting_bucket_index);
let bucket_length = bucket_ref.length();
assert!(
// In the general case, starting vector index should never be equal to bucket length
// because then iteration will attempt to borrow a vector element that is out of bounds.
// However starting vector index can be equal to bucket length in the special case of
// starting iteration at the beginning of an empty bucket since buckets are never
// destroyed, only emptied.
starting_vector_index < bucket_length || starting_vector_index == 0,
EINVALID_VECTOR_INDEX
);
let keys = vector[];
if (num_keys_to_get == 0) return
(keys, option::some(starting_bucket_index), option::some(starting_vector_index));
for (bucket_index in starting_bucket_index..num_buckets) {
bucket_ref = buckets_ref.borrow(bucket_index);
bucket_length = bucket_ref.length();
for (vector_index in starting_vector_index..bucket_length) {
keys.push_back(bucket_ref.borrow(vector_index).key);
num_keys_to_get -= 1;
if (num_keys_to_get == 0) {
vector_index += 1;
return if (vector_index == bucket_length) {
bucket_index += 1;
if (bucket_index < num_buckets) {
(keys, option::some(bucket_index), option::some(0))
} else {
(keys, option::none(), option::none())
}
} else {
(keys, option::some(bucket_index), option::some(vector_index))
}
};
};
starting_vector_index = 0; // Start parsing the next bucket at vector index 0.
};
(keys, option::none(), option::none())
}
Function split_one_bucket
Decide which is the next bucket to split and split it into two with the elements inside the bucket.
fun split_one_bucket<K, V>(self: &mut smart_table::SmartTable<K, V>)
Implementation
fun split_one_bucket<K, V>(self: &mut SmartTable<K, V>) {
let new_bucket_index = self.num_buckets;
// the next bucket to split is num_bucket without the most significant bit.
let to_split = new_bucket_index ^ (1 << self.level);
self.num_buckets = new_bucket_index + 1;
// if the whole level is splitted once, bump the level.
if (to_split + 1 == 1 << self.level) {
self.level += 1;
};
let old_bucket = self.buckets.borrow_mut(to_split);
// partition the bucket, [0..p) stays in old bucket, [p..len) goes to new bucket
let p = old_bucket.partition(|e| {
let entry: &Entry<K, V> = e; // Explicit type to satisfy compiler
bucket_index(self.level, self.num_buckets, entry.hash) != new_bucket_index
});
let new_bucket = old_bucket.trim_reverse(p);
self.buckets.add(new_bucket_index, new_bucket);
}
Function bucket_index
Return the expected bucket index to find the hash.
Basically, it use different base 1 << level vs 1 << (level + 1) in modulo operation based on the target
bucket index compared to the index of the next bucket to split.
fun bucket_index(level: u8, num_buckets: u64, hash: u64): u64
Implementation
fun bucket_index(level: u8, num_buckets: u64, hash: u64): u64 {
let index = hash % (1 << (level + 1));
if (index < num_buckets) {
// in existing bucket
index
} else {
// in unsplitted bucket
index % (1 << level)
}
}
Function borrow
Acquire an immutable reference to the value which key maps to.
Aborts if there is no entry for key.
public fun borrow<K: drop, V>(self: &smart_table::SmartTable<K, V>, key: K): &V
Implementation
public fun borrow<K: drop, V>(self: &SmartTable<K, V>, key: K): &V {
let index = bucket_index(self.level, self.num_buckets, sip_hash_from_value(&key));
let bucket = self.buckets.borrow(index);
let len = bucket.length();
for (i in 0..len) {
let entry = bucket.borrow(i);
if (&entry.key == &key) {
return &entry.value
};
};
abort error::invalid_argument(ENOT_FOUND)
}
Function borrow_with_default
Acquire an immutable reference to the value which key maps to.
Returns specified default value if there is no entry for key.
public fun borrow_with_default<K: copy, drop, V>(self: &smart_table::SmartTable<K, V>, key: K, default: &V): &V
Implementation
public fun borrow_with_default<K: copy + drop, V>(self: &SmartTable<K, V>, key: K, default: &V): &V {
if (!self.contains(copy key)) {
default
} else {
self.borrow(copy key)
}
}
Function borrow_mut
Acquire a mutable reference to the value which key maps to.
Aborts if there is no entry for key.
public fun borrow_mut<K: drop, V>(self: &mut smart_table::SmartTable<K, V>, key: K): &mut V
Implementation
public fun borrow_mut<K: drop, V>(self: &mut SmartTable<K, V>, key: K): &mut V {
let index = bucket_index(self.level, self.num_buckets, sip_hash_from_value(&key));
let bucket = self.buckets.borrow_mut(index);
let len = bucket.length();
for (i in 0..len) {
let entry = bucket.borrow_mut(i);
if (&entry.key == &key) {
return &mut entry.value
};
};
abort error::invalid_argument(ENOT_FOUND)
}
Function borrow_mut_with_default
Acquire a mutable reference to the value which key maps to.
Insert the pair (key, default) first if there is no entry for key.
public fun borrow_mut_with_default<K: copy, drop, V: drop>(self: &mut smart_table::SmartTable<K, V>, key: K, default: V): &mut V
Implementation
public fun borrow_mut_with_default<K: copy + drop, V: drop>(
self: &mut SmartTable<K, V>,
key: K,
default: V
): &mut V {
if (!self.contains(copy key)) {
self.add(copy key, default)
};
self.borrow_mut(key)
}
Function contains
Returns true iff table contains an entry for key.
public fun contains<K: drop, V>(self: &smart_table::SmartTable<K, V>, key: K): bool
Implementation
public fun contains<K: drop, V>(self: &SmartTable<K, V>, key: K): bool {
let hash = sip_hash_from_value(&key);
let index = bucket_index(self.level, self.num_buckets, hash);
let bucket = self.buckets.borrow(index);
bucket.any(| e | {
e.hash == hash && &e.key == &key
})
}
Function remove
Remove from table and return the value which key maps to.
Aborts if there is no entry for key.
public fun remove<K: copy, drop, V>(self: &mut smart_table::SmartTable<K, V>, key: K): V
Implementation
public fun remove<K: copy + drop, V>(self: &mut SmartTable<K, V>, key: K): V {
let index = bucket_index(self.level, self.num_buckets, sip_hash_from_value(&key));
let bucket = self.buckets.borrow_mut(index);
let len = bucket.length();
for (i in 0..len) {
let entry = bucket.borrow(i);
if (&entry.key == &key) {
let Entry { hash: _, key: _, value } = bucket.swap_remove(i);
self.size -= 1;
return value
};
};
abort error::invalid_argument(ENOT_FOUND)
}
Function upsert
Insert the pair (key, value) if there is no entry for key.
update the value of the entry for key to value otherwise
public fun upsert<K: copy, drop, V: drop>(self: &mut smart_table::SmartTable<K, V>, key: K, value: V)
Implementation
public fun upsert<K: copy + drop, V: drop>(self: &mut SmartTable<K, V>, key: K, value: V) {
if (!self.contains(copy key)) {
self.add(copy key, value)
} else {
let ref = self.borrow_mut(key);
*ref = value;
};
}
Function length
Returns the length of the table, i.e. the number of entries.
public fun length<K, V>(self: &smart_table::SmartTable<K, V>): u64
Implementation
public fun length<K, V>(self: &SmartTable<K, V>): u64 {
self.size
}
Function load_factor
Return the load factor of the hashtable.
public fun load_factor<K, V>(self: &smart_table::SmartTable<K, V>): u64
Implementation
public fun load_factor<K, V>(self: &SmartTable<K, V>): u64 {
self.size * 100 / self.num_buckets / self.target_bucket_size
}
Function update_split_load_threshold
Update split_load_threshold.
public fun update_split_load_threshold<K, V>(self: &mut smart_table::SmartTable<K, V>, split_load_threshold: u8)
Implementation
public fun update_split_load_threshold<K, V>(self: &mut SmartTable<K, V>, split_load_threshold: u8) {
assert!(
split_load_threshold <= 100 && split_load_threshold > 0,
error::invalid_argument(EINVALID_LOAD_THRESHOLD_PERCENT)
);
self.split_load_threshold = split_load_threshold;
}
Function update_target_bucket_size
Update target_bucket_size.
public fun update_target_bucket_size<K, V>(self: &mut smart_table::SmartTable<K, V>, target_bucket_size: u64)
Implementation
public fun update_target_bucket_size<K, V>(self: &mut SmartTable<K, V>, target_bucket_size: u64) {
assert!(target_bucket_size > 0, error::invalid_argument(EINVALID_TARGET_BUCKET_SIZE));
self.target_bucket_size = target_bucket_size;
}
Function for_each_ref
Apply the function to a reference of each key-value pair in the table.
public fun for_each_ref<K, V>(self: &smart_table::SmartTable<K, V>, f: |&K, &V|)
Implementation
public inline fun for_each_ref<K, V>(self: &SmartTable<K, V>, f: |&K, &V|) {
for (i in 0..self.num_buckets()) {
self.borrow_buckets().borrow(i).for_each_ref(|elem| {
let (key, value) = elem.borrow_kv();
f(key, value)
});
}
}
Function for_each_mut
Apply the function to a mutable reference of each key-value pair in the table.
public fun for_each_mut<K, V>(self: &mut smart_table::SmartTable<K, V>, f: |&K, &mut V|)
Implementation
public inline fun for_each_mut<K, V>(self: &mut SmartTable<K, V>, f: |&K, &mut V|) {
for (i in 0..self.num_buckets()) {
self.borrow_buckets_mut().borrow_mut(i).for_each_mut(|elem| {
let (key, value) = elem.borrow_kv_mut();
f(key, value)
});
};
}
Function map_ref
Map the function over the references of key-value pairs in the table without modifying it.
public fun map_ref<K: copy, drop, store, V1, V2: store>(self: &smart_table::SmartTable<K, V1>, f: |&V1|V2): smart_table::SmartTable<K, V2>
Implementation
public inline fun map_ref<K: copy + drop + store, V1, V2: store>(
self: &SmartTable<K, V1>,
f: |&V1|V2
): SmartTable<K, V2> {
let new_table = new<K, V2>();
self.for_each_ref(|key, value| new_table.add(*key, f(value)));
new_table
}
Function any
Return true if any key-value pair in the table satisfies the predicate.
public fun any<K, V>(self: &smart_table::SmartTable<K, V>, p: |&K, &V|bool): bool
Implementation
public inline fun any<K, V>(
self: &SmartTable<K, V>,
p: |&K, &V|bool
): bool {
let found = false;
for (i in 0..self.num_buckets()) {
found = self.borrow_buckets().borrow(i).any(|elem| {
let (key, value) = elem.borrow_kv();
p(key, value)
});
if (found) break;
};
found
}
Function borrow_kv
public fun borrow_kv<K, V>(self: &smart_table::Entry<K, V>): (&K, &V)
Implementation
public fun borrow_kv<K, V>(self: &Entry<K, V>): (&K, &V) {
(&self.key, &self.value)
}
Function borrow_kv_mut
public fun borrow_kv_mut<K, V>(self: &mut smart_table::Entry<K, V>): (&mut K, &mut V)
Implementation
public fun borrow_kv_mut<K, V>(self: &mut Entry<K, V>): (&mut K, &mut V) {
(&mut self.key, &mut self.value)
}
Function num_buckets
public fun num_buckets<K, V>(self: &smart_table::SmartTable<K, V>): u64
Implementation
public fun num_buckets<K, V>(self: &SmartTable<K, V>): u64 {
self.num_buckets
}
Function borrow_buckets
public fun borrow_buckets<K, V>(self: &smart_table::SmartTable<K, V>): &table_with_length::TableWithLength<u64, vector<smart_table::Entry<K, V>>>
Implementation
public fun borrow_buckets<K, V>(self: &SmartTable<K, V>): &TableWithLength<u64, vector<Entry<K, V>>> {
&self.buckets
}
Function borrow_buckets_mut
public fun borrow_buckets_mut<K, V>(self: &mut smart_table::SmartTable<K, V>): &mut table_with_length::TableWithLength<u64, vector<smart_table::Entry<K, V>>>
Implementation
public fun borrow_buckets_mut<K, V>(self: &mut SmartTable<K, V>): &mut TableWithLength<u64, vector<Entry<K, V>>> {
&mut self.buckets
}
Specification
Struct SmartTable
struct SmartTable<K, V> has store
-
buckets: table_with_length::TableWithLength<u64, vector<smart_table::Entry<K, V>>> -
num_buckets: u64 -
level: u8 -
size: u64 -
split_load_threshold: u8 -
target_bucket_size: u64
pragma intrinsic = map,
map_new = new,
map_destroy_empty = destroy_empty,
map_len = length,
map_has_key = contains,
map_add_no_override = add,
map_add_override_if_exists = upsert,
map_del_must_exist = remove,
map_borrow = borrow,
map_borrow_mut = borrow_mut,
map_borrow_mut_with_default = borrow_mut_with_default,
map_borrow_with_default = borrow_with_default,
map_spec_get = spec_get,
map_spec_set = spec_set,
map_spec_del = spec_remove,
map_spec_len = spec_len,
map_spec_has_key = spec_contains;
Function new_with_config
public fun new_with_config<K: copy, drop, store, V: store>(num_initial_buckets: u64, split_load_threshold: u8, target_bucket_size: u64): smart_table::SmartTable<K, V>
pragma verify = false;
Function destroy
public fun destroy<K: drop, V: drop>(self: smart_table::SmartTable<K, V>)
pragma verify = false;
pragma opaque;
Function clear
public fun clear<K: drop, V: drop>(self: &mut smart_table::SmartTable<K, V>)
pragma verify = false;
pragma opaque;
Function add_all
public fun add_all<K, V>(self: &mut smart_table::SmartTable<K, V>, keys: vector<K>, values: vector<V>)
pragma verify = false;
Function to_simple_map
public fun to_simple_map<K: copy, drop, store, V: copy, store>(self: &smart_table::SmartTable<K, V>): simple_map::SimpleMap<K, V>
pragma verify = false;
Function keys
public fun keys<K: copy, drop, store, V: copy, store>(self: &smart_table::SmartTable<K, V>): vector<K>
pragma verify = false;
Function keys_paginated
public fun keys_paginated<K: copy, drop, store, V: copy, store>(self: &smart_table::SmartTable<K, V>, starting_bucket_index: u64, starting_vector_index: u64, num_keys_to_get: u64): (vector<K>, option::Option<u64>, option::Option<u64>)
pragma verify = false;
Function split_one_bucket
fun split_one_bucket<K, V>(self: &mut smart_table::SmartTable<K, V>)
pragma verify = false;
Function bucket_index
fun bucket_index(level: u8, num_buckets: u64, hash: u64): u64
pragma verify = false;
Function load_factor
public fun load_factor<K, V>(self: &smart_table::SmartTable<K, V>): u64
pragma verify = false;
Function update_split_load_threshold
public fun update_split_load_threshold<K, V>(self: &mut smart_table::SmartTable<K, V>, split_load_threshold: u8)
pragma verify = false;
Function update_target_bucket_size
public fun update_target_bucket_size<K, V>(self: &mut smart_table::SmartTable<K, V>, target_bucket_size: u64)
pragma verify = false;
Function borrow_kv
public fun borrow_kv<K, V>(self: &smart_table::Entry<K, V>): (&K, &V)
aborts_if false;
ensures result_1 == self.key;
ensures result_2 == self.value;
Function borrow_kv_mut
public fun borrow_kv_mut<K, V>(self: &mut smart_table::Entry<K, V>): (&mut K, &mut V)
aborts_if false;
ensures result_1 == old(self.key);
ensures result_2 == old(self.value);
Function num_buckets
public fun num_buckets<K, V>(self: &smart_table::SmartTable<K, V>): u64
pragma verify = false;
Function borrow_buckets
public fun borrow_buckets<K, V>(self: &smart_table::SmartTable<K, V>): &table_with_length::TableWithLength<u64, vector<smart_table::Entry<K, V>>>
pragma verify = false;
Function borrow_buckets_mut
public fun borrow_buckets_mut<K, V>(self: &mut smart_table::SmartTable<K, V>): &mut table_with_length::TableWithLength<u64, vector<smart_table::Entry<K, V>>>
pragma verify = false;
native fun spec_len<K, V>(t: SmartTable<K, V>): num;
native fun spec_contains<K, V>(t: SmartTable<K, V>, k: K): bool;
native fun spec_set<K, V>(t: SmartTable<K, V>, k: K, v: V): SmartTable<K, V>;
native fun spec_remove<K, V>(t: SmartTable<K, V>, k: K): SmartTable<K, V>;
native fun spec_get<K, V>(t: SmartTable<K, V>, k: K): V;