tasm_lib/list/
split_off.rsuse triton_vm::prelude::*;
use crate::data_type::DataType;
use crate::library::Library;
use crate::memory::dyn_malloc;
use crate::memory::memcpy;
use crate::traits::basic_snippet::BasicSnippet;
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct SplitOff {
pub element_type: DataType,
}
impl SplitOff {
fn self_type(&self) -> DataType {
DataType::List(Box::new(self.element_type.to_owned()))
}
}
impl BasicSnippet for SplitOff {
fn inputs(&self) -> Vec<(DataType, String)> {
vec![
(self.self_type(), "self".to_owned()),
(DataType::U32, "at".to_owned()),
]
}
fn outputs(&self) -> Vec<(DataType, String)> {
vec![(self.self_type(), "other".to_owned())]
}
fn entrypoint(&self) -> String {
format!(
"tasmlib_list_split_off_{}",
self.element_type.label_friendly_name()
)
}
fn code(&self, library: &mut Library) -> Vec<LabelledInstruction> {
let entrypoint = self.entrypoint();
let element_size = self.element_type.stack_size();
let dyn_malloc = library.import(Box::new(dyn_malloc::DynMalloc));
let mem_cpy = library.import(Box::new(memcpy::MemCpy));
triton_asm!(
{entrypoint}:
dup 1
read_mem 1
pop 1
dup 1
dup 1
lt
push 0
eq
assert error_id 80
dup 1
dup 3
write_mem 1
push {element_size}
dup 3
mul
add
call {dyn_malloc}
dup 2
dup 4
push -1
mul
add
dup 0
swap 2
dup 0
swap 7
pop 1
write_mem 1
swap 1
push {element_size}
mul
call {mem_cpy}
pop 2
return
)
}
}
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use rand::prelude::*;
use super::*;
use crate::rust_shadowing_helper_functions::dyn_malloc::dynamic_allocator;
use crate::rust_shadowing_helper_functions::list::insert_random_list;
use crate::rust_shadowing_helper_functions::list::list_set_length;
use crate::rust_shadowing_helper_functions::list::load_list_unstructured;
use crate::snippet_bencher::BenchmarkCase;
use crate::test_helpers::test_assertion_failure;
use crate::traits::function::Function;
use crate::traits::function::FunctionInitialState;
use crate::traits::function::ShadowedFunction;
use crate::traits::rust_shadow::RustShadow;
use crate::InitVmState;
#[test]
fn split_off_pbt() {
for element_type in [
DataType::U32,
DataType::U64,
DataType::Xfe,
DataType::U128,
DataType::Digest,
] {
ShadowedFunction::new(SplitOff { element_type }).test()
}
}
#[test]
fn split_off_negative_test() {
let element_type = DataType::Xfe;
let snippet = SplitOff {
element_type: element_type.clone(),
};
let mut init_stack = snippet.init_stack_for_isolated_run();
let mut memory = HashMap::default();
let mut rng = thread_rng();
let list_pointer: BFieldElement = rng.gen();
init_stack.push(list_pointer);
let list_length = rng.gen_range(0..30);
let at = list_length + 1;
init_stack.push(BFieldElement::new(at as u64));
insert_random_list(&element_type, list_pointer, list_length, &mut memory);
test_assertion_failure(
&ShadowedFunction::new(snippet),
InitVmState::with_stack_and_memory(init_stack, memory),
&[80],
);
}
impl Function for SplitOff {
fn rust_shadow(
&self,
stack: &mut Vec<BFieldElement>,
memory: &mut HashMap<BFieldElement, BFieldElement>,
) {
let at: u32 = stack.pop().unwrap().try_into().unwrap();
let self_vec_pointer = stack.pop().unwrap();
let mut self_vec =
load_list_unstructured(self.element_type.stack_size(), self_vec_pointer, memory);
list_set_length(self_vec_pointer, at as usize, memory);
let other_vec = self_vec.split_off(at as usize);
let other_vec_pointer = dynamic_allocator(memory);
stack.push(other_vec_pointer);
list_set_length(self_vec_pointer, self_vec.len(), memory);
list_set_length(other_vec_pointer, other_vec.len(), memory);
let mut other_vec_word_pointer = other_vec_pointer;
other_vec_word_pointer.increment();
for elem in other_vec.iter() {
for word in elem.iter() {
memory.insert(other_vec_word_pointer, *word);
other_vec_word_pointer.increment();
}
}
}
fn pseudorandom_initial_state(
&self,
seed: [u8; 32],
bench_case: Option<BenchmarkCase>,
) -> FunctionInitialState {
let mut rng: StdRng = StdRng::from_seed(seed);
let mut init_memory = HashMap::default();
let (list_length, at) = match bench_case {
Some(BenchmarkCase::CommonCase) => (100, 50),
Some(BenchmarkCase::WorstCase) => (1000, 0),
None => {
let list_length = rng.gen_range(1..1000);
(list_length, rng.gen_range(0..list_length))
}
};
let list_pointer = rng.gen();
insert_random_list(
&self.element_type,
list_pointer,
list_length,
&mut init_memory,
);
let init_stack = [
self.init_stack_for_isolated_run(),
vec![list_pointer, BFieldElement::new(at as u64)],
]
.concat();
FunctionInitialState {
stack: init_stack,
memory: init_memory,
}
}
}
}
#[cfg(test)]
mod benches {
use super::*;
use crate::traits::function::ShadowedFunction;
use crate::traits::rust_shadow::RustShadow;
#[test]
fn split_off_bench() {
ShadowedFunction::new(SplitOff {
element_type: DataType::Xfe,
})
.bench();
}
}