use crate::push::instructions::{Instruction, InstructionCache};
use crate::push::item::Item;
use crate::push::item::PushType;
use crate::push::state::*;
use crate::push::topology::Topology;
use crate::push::vector::{BoolVector, FloatVector, IntVector};
use std::collections::HashMap;
pub fn load_list_instructions(map: &mut HashMap<String, Instruction>) {
map.insert(String::from("LIST.ADD"), Instruction::new(list_add));
map.insert(String::from("LIST.REMOVE"), Instruction::new(list_remove));
map.insert(String::from("LIST.GET"), Instruction::new(list_get));
map.insert(String::from("LIST.SET"), Instruction::new(list_set));
map.insert(String::from("LIST.BVAL"), Instruction::new(list_bval));
map.insert(String::from("LIST.IVAL"), Instruction::new(list_ival));
map.insert(String::from("LIST.FVAL"), Instruction::new(list_fval));
map.insert(
String::from("LIST.NEIGHBOR*IDS"),
Instruction::new(list_neighbor_ids),
);
map.insert(
String::from("LIST.NEIGHBOR*BVALS"),
Instruction::new(list_neighbor_bvals),
);
map.insert(
String::from("LIST.NEIGHBOR*IVALS"),
Instruction::new(list_neighbor_ivals),
);
map.insert(
String::from("LIST.NEIGHBOR*FVALS"),
Instruction::new(list_neighbor_fvals),
);
}
pub fn bval(item: &Item, n: &usize) -> bool {
let default = false;
match Item::find(item, &Item::bool(false), &mut 0, n) {
Ok(bval) => match bval {
Item::Literal { push_type } => match push_type {
PushType::Bool { val } => return val,
_ => (),
},
_ => (),
},
Err(_cnt) => (),
};
return default;
}
pub fn ival(item: &Item, n: &usize) -> i32 {
let default = 0;
match Item::find(item, &Item::int(0), &mut 0, n) {
Ok(ival) => match ival {
Item::Literal { push_type } => match push_type {
PushType::Int { val } => return val,
_ => (),
},
_ => (),
},
Err(_cnt) => (),
};
return default;
}
pub fn fval(item: &Item, n: &usize) -> f32 {
let default = 0.0;
match Item::find(item, &Item::float(0.0), &mut 0, n) {
Ok(fval) => match fval {
Item::Literal { push_type } => match push_type {
PushType::Float { val } => return val,
_ => (),
},
_ => (),
},
Err(_cnt) => (),
};
return default;
}
pub fn load_items(push_state: &mut PushState) -> Option<Vec<Item>> {
if let Some(stack_ids) = push_state.int_vector_stack.pop() {
let mut items = vec![];
for &sid in &stack_ids.values {
match sid {
BOOL_STACK_ID => {
if let Some(bi) = push_state.bool_stack.pop() {
items.push(Item::bool(bi));
}
}
BOOL_VECTOR_STACK_ID => {
if let Some(bvi) = push_state.bool_vector_stack.pop() {
items.push(Item::boolvec(bvi));
}
}
CODE_STACK_ID => {
if let Some(ci) = push_state.code_stack.pop() {
items.push(ci);
}
}
EXEC_STACK_ID => {
if let Some(ei) = push_state.exec_stack.pop() {
items.push(ei);
}
}
FLOAT_STACK_ID => {
if let Some(fi) = push_state.float_stack.pop() {
items.push(Item::float(fi));
}
}
FLOAT_VECTOR_STACK_ID => {
if let Some(fvi) = push_state.float_vector_stack.pop() {
items.push(Item::floatvec(fvi));
}
}
INT_STACK_ID => {
if let Some(ii) = push_state.int_stack.pop() {
items.push(Item::int(ii));
}
}
INT_VECTOR_STACK_ID => {
if let Some(ivi) = push_state.int_vector_stack.pop() {
items.push(Item::intvec(ivi));
}
}
NAME_STACK_ID => {
if let Some(ni) = push_state.name_stack.pop() {
items.push(Item::name(ni));
}
}
_ => (),
}
}
return Some(items);
}
return None;
}
pub fn new_list(push_state: &mut PushState) -> Option<Vec<Item>> {
if let Some(items) = load_items(push_state) {
return Some(items);
}
return None;
}
pub fn list_add(push_state: &mut PushState, _instruction_set: &InstructionCache) {
if let Some(items) = new_list(push_state) {
let list_item = Item::list(items);
push_state.code_stack.push(list_item);
}
}
pub fn list_remove(push_state: &mut PushState, _instruction_set: &InstructionCache) {
if let Some(index) = push_state.int_stack.pop() {
let size = push_state.code_stack.size() as i32;
let list_index = i32::max(i32::min(size - 1, index), 0) as usize;
push_state.code_stack.remove(list_index);
}
}
pub fn list_get(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
if let Some(index) = push_state.int_stack.pop() {
let size = push_state.code_stack.size() as i32;
let list_index = i32::max(i32::min(size - 1, index), 0) as usize;
if let Some(list) = push_state.code_stack.copy(list_index) {
match list {
Item::List { items } => {
push_state.exec_stack.push(Item::List { items: items });
}
_ => (),
}
}
}
}
pub fn list_bval(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
if let Some(index) = push_state.int_stack.pop_vec(2) {
let size = push_state.code_stack.size() as i32;
let list_index = i32::max(i32::min(size - 1, index[0]), 0) as usize;
if let Some(list_item) = push_state.code_stack.get(list_index) {
push_state
.bool_stack
.push(bval(list_item, &(index[1] as usize)));
}
}
}
pub fn list_ival(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
if let Some(index) = push_state.int_stack.pop_vec(2) {
let size = push_state.code_stack.size() as i32;
let list_index = i32::max(i32::min(size - 1, index[0]), 0) as usize;
if let Some(list_item) = push_state.code_stack.get(list_index) {
push_state
.int_stack
.push(ival(list_item, &(index[1] as usize)));
}
}
}
pub fn list_fval(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
if let Some(index) = push_state.int_stack.pop_vec(2) {
let size = push_state.code_stack.size() as i32;
let list_index = i32::max(i32::min(size - 1, index[0]), 0) as usize;
if let Some(list_item) = push_state.code_stack.get(list_index) {
push_state
.float_stack
.push(fval(list_item, &(index[1] as usize)));
}
}
}
pub fn list_set(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
if let Some(index) = push_state.int_stack.pop() {
let size = push_state.code_stack.size() as i32;
let list_index = i32::max(i32::min(size - 1, index), 0) as usize;
if let Some(items) = load_items(push_state) {
let list_item = Item::list(items);
let _res = push_state.code_stack.replace(list_index, list_item);
}
}
}
pub fn list_neighbor_ids(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
if let Some(topology) = push_state.int_stack.pop_vec(3) {
let size = i32::max(topology[2], 0);
let index = i32::max(i32::min(size - 1, topology[1]), 0) as usize;
let dimensions = i32::max(i32::min(size, topology[0]), 0) as usize;
if let Some(fval) = push_state.float_stack.pop() {
let radius = f32::max(fval, 0.0);
if let Some(neighbors) =
Topology::find_neighbors(&(size as usize), &dimensions, &index, &radius)
{
let mut result = vec![];
for n in neighbors.values.iter() {
result.push(*n);
}
push_state.int_vector_stack.push(IntVector::new(result));
}
}
}
}
pub fn list_neighbor_bvals(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
if let Some(topology) = push_state.int_stack.pop_vec(4) {
let position = topology[3] as usize;
let size = i32::max(topology[2], 0);
let index = i32::max(i32::min(size - 1, topology[1]), 0) as usize;
let dimensions = i32::max(i32::min(size, topology[0]), 0) as usize;
if let Some(fval) = push_state.float_stack.pop() {
let radius = f32::max(fval, 0.0);
if let Some(neighbors) =
Topology::find_neighbors(&(size as usize), &dimensions, &index, &radius)
{
let mut result = vec![];
for n in neighbors.values.iter() {
if let Some(item) = push_state.code_stack.get(*n as usize) {
result.push(bval(item, &position));
}
}
push_state.bool_vector_stack.push(BoolVector::new(result));
}
}
}
}
pub fn list_neighbor_ivals(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
if let Some(topology) = push_state.int_stack.pop_vec(4) {
let position = topology[3] as usize;
let size = i32::max(topology[2], 0);
let index = i32::max(i32::min(size - 1, topology[1]), 0) as usize;
let dimensions = i32::max(i32::min(size, topology[0]), 0) as usize;
if let Some(fval) = push_state.float_stack.pop() {
let radius = f32::max(fval, 0.0);
if let Some(neighbors) =
Topology::find_neighbors(&(size as usize), &dimensions, &index, &radius)
{
let mut result = vec![];
for n in neighbors.values.iter() {
if let Some(item) = push_state.code_stack.get(*n as usize) {
result.push(ival(item, &position));
}
}
push_state.int_vector_stack.push(IntVector::new(result));
}
}
}
}
pub fn list_neighbor_fvals(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
if let Some(topology) = push_state.int_stack.pop_vec(4) {
let position = topology[3] as usize;
let size = i32::max(topology[2], 0);
let index = i32::max(i32::min(size - 1, topology[1]), 0) as usize;
let dimensions = i32::max(i32::min(size, topology[0]), 0) as usize;
if let Some(rval) = push_state.float_stack.pop() {
let radius = f32::max(rval, 0.0);
if let Some(neighbors) =
Topology::find_neighbors(&(size as usize), &dimensions, &index, &radius)
{
let mut result = vec![];
for n in neighbors.values.iter() {
if let Some(item) = push_state.code_stack.get(*n as usize) {
result.push(fval(item, &position));
}
}
push_state.float_vector_stack.push(FloatVector::new(result));
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::push::instructions::InstructionSet;
use crate::push::interpreter::{PushInterpreter, PushInterpreterState};
use crate::push::vector::*;
pub fn icache() -> InstructionCache {
InstructionCache::new(vec![])
}
pub fn litem(i: i32) -> Item {
Item::list(vec![Item::int(i)])
}
#[test]
fn list_add_from_different_stacks() {
let mut test_state = PushState::new();
test_state.bool_stack.push(true);
test_state.int_stack.push(1);
test_state.float_stack.push(1.0);
test_state
.float_vector_stack
.push(FloatVector::new(vec![3.0]));
test_state
.bool_vector_stack
.push(BoolVector::from_int_array(vec![1]));
test_state.int_vector_stack.push(IntVector::new(vec![22]));
test_state.int_vector_stack.push(IntVector::new(vec![
BOOL_STACK_ID,
FLOAT_STACK_ID,
FLOAT_VECTOR_STACK_ID,
BOOL_VECTOR_STACK_ID,
INT_VECTOR_STACK_ID,
INT_STACK_ID,
]));
list_add(&mut test_state, &icache());
assert_eq!(test_state.code_stack.to_string(), "( 1 [22] [TRUE] [3.000] 1.000 TRUE )");
}
#[test]
fn list_remove_code_items() {
let mut test_state = PushState::new();
test_state.code_stack.push(Item::int(1));
test_state.code_stack.push(Item::list(vec![
Item::bool(true),
Item::int(2),
Item::int(3),
Item::float(2.3),
]));
test_state.code_stack.push(Item::int(2));
test_state.int_stack.push(1);
list_remove(&mut test_state, &icache());
assert_eq!(
test_state.code_stack.to_string(),
"2 1"
);
}
#[test]
fn list_get_pushes_code_items() {
let mut test_state = PushState::new();
test_state.code_stack.push(Item::int(1));
test_state.code_stack.push(Item::list(vec![
Item::bool(true),
Item::int(2),
Item::int(3),
Item::float(2.3),
]));
test_state.code_stack.push(Item::int(2));
test_state.int_stack.push(1);
list_get(&mut test_state, &icache());
assert_eq!(
test_state.exec_stack.to_string(),
"( 2.300 3 2 TRUE )",
"Order of elements should be reversed"
);
}
#[test]
fn list_bval_returns_first_int_element() {
let mut test_state = PushState::new();
test_state
.code_stack
.push(Item::list(vec![Item::bool(true), Item::int(2)]));
test_state.int_stack.push(0); test_state.int_stack.push(0); list_bval(&mut test_state, &icache());
assert_eq!(test_state.bool_stack.pop().unwrap(), true);
}
#[test]
fn list_ival_returns_first_int_element() {
let mut test_state = PushState::new();
test_state
.code_stack
.push(Item::list(vec![Item::int(1), Item::int(2)]));
test_state.int_stack.push(0); test_state.int_stack.push(0); list_ival(&mut test_state, &icache());
assert_eq!(test_state.int_stack.pop().unwrap(), 2);
}
#[test]
fn list_fval_returns_first_float_element() {
let mut test_state = PushState::new();
test_state
.code_stack
.push(Item::list(vec![Item::float(1.0), Item::int(2)]));
test_state.int_stack.push(0); test_state.int_stack.push(0); list_fval(&mut test_state, &icache());
assert_eq!(test_state.float_stack.pop().unwrap(), 1.0);
}
#[test]
fn list_set_replaces_code_item() {
let mut test_state = PushState::new();
test_state.bool_stack.push(true);
test_state.bool_stack.push(false);
test_state
.int_vector_stack
.push(IntVector::new(vec![BOOL_STACK_ID, BOOL_STACK_ID]));
test_state.int_stack.push(1);
test_state.code_stack.push(Item::int(11));
test_state.code_stack.push(Item::int(22));
test_state.code_stack.push(Item::int(33));
list_set(&mut test_state, &icache());
assert_eq!(
test_state.code_stack.to_string(),
"33 ( TRUE FALSE ) 11",
"Order of new list element reversed"
);
}
#[test]
fn list_add_get_preserves_stack_positions() {
let mut test_state = PushState::new();
test_state.bool_stack.push(true);
test_state.bool_stack.push(false);
assert_eq!(
test_state.bool_stack.to_string(),
"FALSE TRUE",
"Initial order of items"
);
test_state
.int_vector_stack
.push(IntVector::new(vec![BOOL_STACK_ID, BOOL_STACK_ID]));
list_add(&mut test_state, &icache());
test_state.int_stack.push(0);
list_get(&mut test_state, &icache());
let mut instruction_set = InstructionSet::new();
instruction_set.load();
assert_eq!(
PushInterpreter::run(&mut test_state, &mut instruction_set),
PushInterpreterState::NoErrors
);
assert_eq!(
test_state.bool_stack.to_string(),
"FALSE TRUE",
"Push/Pull of list preserves order of items"
);
}
#[test]
fn list_set_get_preserves_stack_positions() {
let mut test_state = PushState::new();
test_state.bool_stack.push(true);
test_state.bool_stack.push(false);
assert_eq!(
test_state.bool_stack.to_string(),
"FALSE TRUE",
"Initial order of items"
);
test_state
.int_vector_stack
.push(IntVector::new(vec![BOOL_STACK_ID, BOOL_STACK_ID]));
test_state.int_stack.push(1);
test_state.code_stack.push(Item::int(11));
test_state.code_stack.push(Item::int(22));
test_state.code_stack.push(Item::int(33));
list_set(&mut test_state, &icache());
test_state.int_stack.push(1);
list_get(&mut test_state, &icache());
let mut instruction_set = InstructionSet::new();
instruction_set.load();
assert_eq!(
PushInterpreter::run(&mut test_state, &mut instruction_set),
PushInterpreterState::NoErrors
);
assert_eq!(
test_state.bool_stack.to_string(),
"FALSE TRUE",
"Push/Pull of list preserves order of items"
);
}
#[test]
fn list_neighbor_ids_pushes_result_for_valid_index() {
let mut test_state = PushState::new();
test_state.float_stack.push(1.5); test_state.int_stack.push(2); test_state.int_stack.push(50); test_state.int_stack.push(100); list_neighbor_ids(&mut test_state, &icache());
assert_eq!(
test_state.int_vector_stack.to_string(),
String::from("[40,41,50,51,60,61]")
);
}
#[test]
fn list_neighbor_ids_corrects_out_of_bounds_index() {
let mut test_state = PushState::new();
test_state.float_stack.push(1.5); test_state.int_stack.push(2); test_state.int_stack.push(105); test_state.int_stack.push(100); list_neighbor_ids(&mut test_state, &icache());
assert_eq!(
test_state.int_vector_stack.to_string(),
String::from("[88,89,98,99]")
);
test_state.int_vector_stack.flush();
test_state.float_stack.push(1.5); test_state.int_stack.push(2); test_state.int_stack.push(-10); test_state.int_stack.push(100); list_neighbor_ids(&mut test_state, &icache());
assert_eq!(
test_state.int_vector_stack.to_string(),
String::from("[0,1,10,11]")
);
}
#[test]
fn list_neighbor_ivals_pushes_sort_values() {
let mut test_state = PushState::new();
test_state.float_stack.push(1.0); test_state.int_stack.push(2); test_state.int_stack.push(0); test_state.int_stack.push(9); for i in 10..20 {
test_state.code_stack.push(litem(i));
}
list_neighbor_ids(&mut test_state, &icache());
assert_eq!(
test_state.int_vector_stack.to_string(),
String::from("[0,1,3]")
);
test_state.int_vector_stack.flush();
test_state.float_stack.push(1.0); test_state.int_stack.push(2); test_state.int_stack.push(0); test_state.int_stack.push(9); test_state.int_stack.push(0); list_neighbor_ivals(&mut test_state, &icache());
assert_eq!(
test_state.int_vector_stack.to_string(),
String::from("[19,18,16]")
);
}
}