Commit 86d46690 authored by Christopher Silva's avatar Christopher Silva

switch changes vec to hashmap/finish basic processing_changes

parent cc7c8ffe
/target
**/*.rs.bk
.idea/
use std::str::FromStr;
use anyhow::Result;
use rust_decimal::prelude::*;
use rust_decimal::Decimal;
use spreadsheet::function;
use spreadsheet::workbook::Workbook;
fn main() {
fn main() -> Result<()> {
let mut workbook = Workbook::new();
let sheet = workbook.add_sheet("Test".into());
......@@ -16,6 +17,7 @@ fn main() {
sheet.write_text(i, j, format!("text {} {}", i, j)).unwrap();
}
}
sheet.process_changes()?;
println!("rendering ranges");
for i in 0..10 {
......@@ -31,8 +33,7 @@ fn main() {
sheet.write_number(i, j, format!("{}", (100 * i + j) as i32)).unwrap();
}
}
sheet.process_changes();
sheet.process_changes()?;
let range = sheet.range(0, 0, 10, 10);
let sum = function::sum(range.clone());
......@@ -40,7 +41,7 @@ fn main() {
let count = function::count(range.clone());
let max = function::max(range.clone());
let min = function::min(range);
println!("sum,count,max,min of r0c0:r9c9: {} {} {} {} {}", sum, avg, count, max, min);
println!("sum,avg,count,max,min of r0c0:r9c9: {} {} {} {} {}", sum, avg, count, max, min);
let dec = Decimal::from_str("3.1415").unwrap();
let dec2 = Decimal::from_str("18").unwrap();
......@@ -52,16 +53,48 @@ fn main() {
sheet.write_formula(10, 10, "=sum(r0c0:r9c9)".to_string()).unwrap();
println!("sum(r10c10:r10c10): {:?}", sheet.render_range(10, 10, 1, 1));
sheet.write_formula(10, 10, "=avg(r0c0:r9c9)".to_string()).unwrap();
println!("avg(r10c10:r10c10): {:?}", sheet.render_range(10, 10, 1, 1));
sheet.write_formula(10, 10, "=count(r0c0:r9c9)".to_string()).unwrap();
println!("count(r10c10:r10c10): {:?}", sheet.render_range(10, 10, 1, 1));
sheet.write_formula(10, 10, "=max(r0c0:r9c9)".to_string()).unwrap();
println!("max(r10c10:r10c10): {:?}", sheet.render_range(10, 10, 1, 1));
sheet.write_formula(10, 10, "=min(r0c0:r9c9)".to_string()).unwrap();
println!("min(r10c10:r10c10): {:?}", sheet.render_range(10, 10, 1, 1));
sheet.write_formula(11, 10, "=avg(r0c0:r9c9)".to_string()).unwrap();
println!("avg(r10c10:r10c10): {:?}", sheet.render_range(11, 10, 1, 1));
sheet.write_formula(12, 10, "=count(r0c0:r9c9)".to_string()).unwrap();
println!("count(r10c10:r10c10): {:?}", sheet.render_range(12, 10, 1, 1));
sheet.write_formula(13, 10, "=max(r0c0:r9c9)".to_string()).unwrap();
println!("max(r10c10:r10c10): {:?}", sheet.render_range(13, 10, 1, 1));
sheet.write_formula(14, 10, "=min(r0c0:r9c9)".to_string()).unwrap();
println!("min(r10c10:r10c10): {:?}", sheet.render_range(14, 10, 1, 1));
sheet.process_changes();
sheet.process_changes()?;
println!("changing value in (0, 0)");
sheet.write_number(0, 0, "42".into()).unwrap();
sheet.process_changes()?;
println!("sum(r10c10:r10c10): {:?}", sheet.render_range(10, 10, 1, 1));
println!("avg(r10c10:r10c10): {:?}", sheet.render_range(11, 10, 1, 1));
println!("count(r10c10:r10c10): {:?}", sheet.render_range(12, 10, 1, 1));
println!("max(r10c10:r10c10): {:?}", sheet.render_range(13, 10, 1, 1));
println!("min(r10c10:r10c10): {:?}", sheet.render_range(14, 10, 1, 1));
println!("deleting value in (0, 0)");
sheet.delete_cell(0, 0);
sheet.process_changes()?;
println!("sum(r10c10:r10c10): {:?}", sheet.render_range(10, 10, 1, 1));
println!("avg(r10c10:r10c10): {:?}", sheet.render_range(11, 10, 1, 1));
println!("count(r10c10:r10c10): {:?}", sheet.render_range(12, 10, 1, 1));
println!("max(r10c10:r10c10): {:?}", sheet.render_range(13, 10, 1, 1));
println!("min(r10c10:r10c10): {:?}", sheet.render_range(14, 10, 1, 1));
println!("changing value in (10, 10)");
sheet.delete_cell(10, 10);
sheet.process_changes()?;
println!("deleted cell: {:?}", sheet.render_range(10, 10, 1, 1));
println!("avg(r10c10:r10c10): {:?}", sheet.render_range(11, 10, 1, 1));
println!("count(r10c10:r10c10): {:?}", sheet.render_range(12, 10, 1, 1));
println!("max(r10c10:r10c10): {:?}", sheet.render_range(13, 10, 1, 1));
println!("min(r10c10:r10c10): {:?}", sheet.render_range(14, 10, 1, 1));
Ok(())
}
fn pow(x: Decimal, y: Decimal) -> Decimal {
......
use std::collections::HashMap;
use std::str::FromStr;
use anyhow::Result;
use anyhow::{Result, bail};
use petgraph::Direction;
use petgraph::graphmap::DiGraphMap;
use rayon::prelude::*;
use rust_decimal::Decimal;
......@@ -16,10 +17,10 @@ pub type RenderedRange = Vec<Vec<String>>;
#[derive(Clone, Debug)]
enum Change {
Create((usize, usize), Cell),
Update((usize, usize), Cell),
Reference((usize, usize)),
Delete((usize, usize))
Create(Cell),
Update(Cell),
Reference,
Delete,
}
use Change::*;
......@@ -27,7 +28,7 @@ use Change::*;
pub struct Sheet {
name: String,
cells: HashMap<(usize, usize), Cell>,
changes: Vec<Change>,
changes: HashMap<(usize, usize), Change>,
references: DiGraphMap<(usize, usize), usize>,
}
......@@ -35,9 +36,9 @@ macro_rules! write_func {
($name:ident, true, $closure:expr) => {
pub fn $name(&mut self, r: usize, c: usize, value: String) -> Result<()> {
let cell = $closure(self, r, c, value)?;
self.changes.push(match self.cells.contains_key(&(r, c)) {
true => Update((r, c), cell.clone()),
false => Create((r, c), cell.clone()),
self.changes.insert((r, c), match self.cells.contains_key(&(r, c)) {
true => Update(cell.clone()),
false => Create(cell.clone()),
});
self.cells.insert((r, c), cell);
Ok(())
......@@ -46,9 +47,9 @@ macro_rules! write_func {
($name:ident, false, $closure:expr) => {
pub fn $name(&mut self, r: usize, c: usize, value: String) -> Result<()> {
let cell = $closure(value)?;
self.changes.push(match self.cells.contains_key(&(r, c)) {
true => Update((r, c), cell.clone()),
false => Create((r, c), cell.clone()),
self.changes.insert((r, c), match self.cells.contains_key(&(r, c)) {
true => Update(cell.clone()),
false => Create(cell.clone()),
});
self.cells.insert((r, c), cell);
Ok(())
......@@ -61,7 +62,7 @@ impl Sheet {
Sheet {
name,
cells: HashMap::new(),
changes: Vec::new(),
changes: HashMap::new(),
references: DiGraphMap::new(),
}
}
......@@ -95,49 +96,63 @@ impl Sheet {
pub fn delete_cell(&mut self, r: usize, c: usize) {
if let Some(_) = self.cells.remove(&(r, c)) {
self.changes.push(Delete((r, c)));
self.changes.insert((r, c), Delete);
}
}
pub fn process_changes(&mut self) {
pub fn process_changes(&mut self) -> Result<()> {
while self.changes.len() != 0 {
let changes = self.changes.clone();
self.changes = Vec::new();
println!("processing {} changes", changes.len());
for change in changes {
// get index of changed cell
let (r, c) = match change.clone() {
Create(index, _) => index,
Update(index, _) => index,
Reference(index) => index,
Delete(index) => index,
};
// do update for current cell if needed (should just be for formulas?)
// get its neighbors and push reference updates to them
// many cells might be changed at once and a cell would
// get multiple reference changes, should the queue be
// changed to a hashmap?
// could this cause issues with syncing the modified cells with formulas?
let neighbors = self.references.neighbors((r, c));
for neighbor in neighbors {
self.changes.push(Reference(neighbor));
self.changes = HashMap::new();
println!("processing {} changes", changes.len());
for (index, change) in changes {
match change.clone() {
Reference => {
let formula = match self.cells.get(&index) {
Some(Formula(formula, _)) => formula.to_owned(),
_ => bail!("non formula cell referenced another cell"),
};
let result = {
let call = formula::parse(formula.clone())?;
let range = self.range(call.r, call.c, call.h, call.w);
function::call(call.function, range)
};
self.cells.insert(index, Formula(formula, Box::new(result)));
},
_ => {},
}
{
let neighbors = self.references.neighbors(index);
for neighbor in neighbors {
self.changes.insert(neighbor, Reference);
}
}
// remove node from references if change was a delete
// but only if there are no other nodes that reference it right?
// otherewise a cell that is referenced could be cleared then written to
// otherwise a cell that is referenced could be cleared then written to
// and the thing that references it wouldn't get that data
match change {
Create(_, _) => {},
Update(_, _) => {},
Reference(_) => {},
Delete(_) => {},
Delete => {
let neighbors = self.references
.neighbors_directed(index, Direction::Incoming)
.collect::<Vec<(usize, usize)>>();
for neighbor in neighbors {
self.references.remove_edge(neighbor, index);
}
if self.references.neighbors(index).count() == 0 {
println!("removing deleted unreferenced node {:?} from references", index);
self.references.remove_node(index);
}
},
_ => {},
}
}
}
println!("done");
Ok(())
}
pub fn range(&self, r: usize, c: usize, h: usize, w: usize) -> Range {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment