Change Dim from usize to Rc<String>

This commit is contained in:
Tiffany Bennett 2016-08-12 20:41:53 -04:00
parent 4f7454209f
commit e92464d8cd
2 changed files with 24 additions and 22 deletions

View file

@ -6,6 +6,7 @@ use number::{Number, Unit};
use date; use date;
use unit_defs::DatePattern; use unit_defs::DatePattern;
use std::ops::{Add, Div, Mul, Neg, Sub}; use std::ops::{Add, Div, Mul, Neg, Sub};
use std::rc::Rc;
#[derive(Clone)] #[derive(Clone)]
pub enum Value { pub enum Value {
@ -15,7 +16,7 @@ pub enum Value {
/// The evaluation context that contains unit definitions. /// The evaluation context that contains unit definitions.
pub struct Context { pub struct Context {
pub dimensions: Vec<String>, pub dimensions: Vec<Rc<String>>,
pub units: HashMap<String, Number>, pub units: HashMap<String, Number>,
pub aliases: HashMap<Unit, String>, pub aliases: HashMap<Unit, String>,
pub prefixes: Vec<(String, Number)>, pub prefixes: Vec<(String, Number)>,
@ -124,9 +125,9 @@ impl Context {
/// Given a unit name, returns its value if it exists. Supports SI /// Given a unit name, returns its value if it exists. Supports SI
/// prefixes, plurals, bare dimensions like length, and aliases. /// prefixes, plurals, bare dimensions like length, and aliases.
pub fn lookup(&self, name: &str) -> Option<Number> { pub fn lookup(&self, name: &str) -> Option<Number> {
for (i, ref k) in self.dimensions.iter().enumerate() { for k in &self.dimensions {
if name == *k { if name == &***k {
return Some(Number::one_unit(i)) return Some(Number::one_unit(k.to_owned()))
} }
} }
self.units.get(name).cloned().or_else(|| { self.units.get(name).cloned().or_else(|| {
@ -164,18 +165,18 @@ impl Context {
} else { } else {
let mut frac = vec![]; let mut frac = vec![];
let mut found = false; let mut found = false;
for (&dim, &pow) in &value.1 { for (dim, &pow) in &value.1 {
if pow < 0 { if pow < 0 {
frac.push((dim, -pow)); frac.push((dim, -pow));
} else { } else {
found = true; found = true;
let mut map = Unit::new(); let mut map = Unit::new();
map.insert(dim, pow); map.insert(dim.clone(), pow);
if let Some(name) = self.aliases.get(&map) { if let Some(name) = self.aliases.get(&map) {
write!(buf, " {}", name).unwrap(); write!(buf, " {}", name).unwrap();
} else { } else {
let mut map = Unit::new(); let mut map = Unit::new();
map.insert(dim, 1); map.insert(dim.clone(), 1);
write!(buf, " {}", self.aliases[&map]).unwrap(); write!(buf, " {}", self.aliases[&map]).unwrap();
if pow != 1 { if pow != 1 {
write!(buf, "^{}", pow).unwrap(); write!(buf, "^{}", pow).unwrap();
@ -191,12 +192,12 @@ impl Context {
} }
for (dim, pow) in frac { for (dim, pow) in frac {
let mut map = Unit::new(); let mut map = Unit::new();
map.insert(dim, pow); map.insert(dim.clone(), pow);
if let Some(name) = self.aliases.get(&map) { if let Some(name) = self.aliases.get(&map) {
write!(buf, " {}", name).unwrap(); write!(buf, " {}", name).unwrap();
} else { } else {
let mut map = Unit::new(); let mut map = Unit::new();
map.insert(dim, 1); map.insert(dim.clone(), 1);
write!(buf, " {}", self.aliases[&map]).unwrap(); write!(buf, " {}", self.aliases[&map]).unwrap();
if pow != 1 { if pow != 1 {
write!(buf, "^{}", pow).unwrap(); write!(buf, "^{}", pow).unwrap();
@ -441,10 +442,10 @@ impl Context {
for (name, def) in defs.defs { for (name, def) in defs.defs {
match *def { match *def {
Def::Dimension(ref dname) => { Def::Dimension(ref dname) => {
let i = ctx.dimensions.len(); let dname = Rc::new(dname.clone());
ctx.dimensions.push(dname.clone()); ctx.dimensions.push(dname.clone());
let mut map = Unit::new(); let mut map = Unit::new();
map.insert(i, 1); map.insert(dname, 1);
ctx.aliases.insert(map, name.clone()); ctx.aliases.insert(map, name.clone());
}, },
Def::Unit(ref expr) => match ctx.eval(expr) { Def::Unit(ref expr) => match ctx.eval(expr) {

View file

@ -3,11 +3,12 @@ use gmp::mpz::Mpz;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use eval::Show; use eval::Show;
use std::ops::{Add, Div, Mul, Neg, Sub}; use std::ops::{Add, Div, Mul, Neg, Sub};
use std::rc::Rc;
/// Number type /// Number type
pub type Num = Mpq; pub type Num = Mpq;
/// A simple alias to add semantic meaning for when we pass around dimension IDs. /// A simple alias to add semantic meaning for when we pass around dimension IDs.
pub type Dim = usize; pub type Dim = Rc<String>;
/// Alias for the primary representation of dimensionality. /// Alias for the primary representation of dimensionality.
pub type Unit = BTreeMap<Dim, i64>; pub type Unit = BTreeMap<Dim, i64>;
@ -170,14 +171,14 @@ impl Number {
pub fn invert(&self) -> Number { pub fn invert(&self) -> Number {
Number(&one() / &self.0, Number(&one() / &self.0,
self.1.iter() self.1.iter()
.map(|(&k, &power)| (k, -power)) .map(|(k, &power)| (k.clone(), -power))
.collect::<Unit>()) .collect::<Unit>())
} }
/// Raises a value to a dimensionless integer power. /// Raises a value to a dimensionless integer power.
pub fn powi(&self, exp: i32) -> Number { pub fn powi(&self, exp: i32) -> Number {
let unit = self.1.iter() let unit = self.1.iter()
.map(|(&k, &power)| (k, power * exp as i64)) .map(|(k, &power)| (k.clone(), power * exp as i64))
.collect::<Unit>(); .collect::<Unit>();
Number(pow(&self.0, exp), unit) Number(pow(&self.0, exp), unit)
} }
@ -186,11 +187,11 @@ impl Number {
/// powers divisible by n. /// powers divisible by n.
pub fn root(&self, exp: i32) -> Option<Number> { pub fn root(&self, exp: i32) -> Option<Number> {
let mut res = Unit::new(); let mut res = Unit::new();
for (&dim, &power) in &self.1 { for (dim, &power) in &self.1 {
if power % exp as i64 != 0 { if power % exp as i64 != 0 {
return None return None
} else { } else {
res.insert(dim, power / exp as i64); res.insert(dim.clone(), power / exp as i64);
} }
} }
Some(Number(root(&self.0, exp), res)) Some(Number(root(&self.0, exp), res))
@ -256,11 +257,11 @@ impl Show for Number {
value.0.canonicalize(); value.0.canonicalize();
write!(out, "{}", self.show_number_part()).unwrap(); write!(out, "{}", self.show_number_part()).unwrap();
for (&dim, &exp) in &value.1 { for (dim, &exp) in &value.1 {
if exp < 0 { if exp < 0 {
frac.push((dim, exp)); frac.push((dim.clone(), exp));
} else { } else {
write!(out, " {}", context.dimensions[dim]).unwrap(); write!(out, " {}", dim).unwrap();
if exp != 1 { if exp != 1 {
write!(out, "^{}", exp).unwrap(); write!(out, "^{}", exp).unwrap();
} }
@ -270,7 +271,7 @@ impl Show for Number {
write!(out, " /").unwrap(); write!(out, " /").unwrap();
for (dim, exp) in frac { for (dim, exp) in frac {
let exp = -exp; let exp = -exp;
write!(out, " {}", context.dimensions[dim]).unwrap(); write!(out, " {}", dim).unwrap();
if exp != 1 { if exp != 1 {
write!(out, "^{}", exp).unwrap(); write!(out, "^{}", exp).unwrap();
} }
@ -279,9 +280,9 @@ impl Show for Number {
let alias = context.aliases.get(&value.1).cloned().or_else(|| { let alias = context.aliases.get(&value.1).cloned().or_else(|| {
if value.1.len() == 1 { if value.1.len() == 1 {
let e = value.1.iter().next().unwrap(); let e = value.1.iter().next().unwrap();
let ref n = context.dimensions[*e.0]; let ref n = *e.0;
if *e.1 == 1 { if *e.1 == 1 {
Some(n.clone()) Some((**n).clone())
} else { } else {
Some(format!("{}^{}", n, e.1)) Some(format!("{}^{}", n, e.1))
} }