-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #33 from orxfun/imp_push_get_ref
`imp_push_get_ref` is implemented
- Loading branch information
Showing
6 changed files
with
378 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
use orx_imp_vec::*; | ||
use std::{ | ||
fmt::{Display, Formatter, Result}, | ||
ops::{Add, Index, Mul}, | ||
}; | ||
|
||
/// # Scope | ||
/// | ||
/// It is a bag of things, | ||
/// analogous to variables, expressions, etc. defined | ||
/// in the scope of a code block. | ||
#[derive(Default)] | ||
struct Scope<'a> { | ||
vectors: ImpVec<Vector<'a>>, | ||
exprs: ImpVec<Expr<'a>>, | ||
terms: ImpVec<Term<'a>>, | ||
vars: ImpVec<Var<'a>>, | ||
} | ||
|
||
impl<'a> Scope<'a> { | ||
fn same_scope_as(&self, other: &Self) -> bool { | ||
self as *const Self == other as *const Self | ||
} | ||
} | ||
|
||
impl<'a> Scope<'a> { | ||
fn new_var_vec(&'a self, symbol: &str) -> &'a Vector<'a> { | ||
self.vectors.imp_push_get_ref(Vector { | ||
scope: self, | ||
symbol: symbol.to_string(), | ||
}) | ||
} | ||
} | ||
|
||
/// # VarVec | ||
struct Vector<'a> { | ||
scope: &'a Scope<'a>, | ||
symbol: String, | ||
} | ||
|
||
impl<'a> Display for Vector<'a> { | ||
fn fmt(&self, f: &mut Formatter<'_>) -> Result { | ||
write!(f, "{}", self.symbol) | ||
} | ||
} | ||
|
||
impl<'a> Index<usize> for &'a Vector<'a> { | ||
type Output = Var<'a>; | ||
|
||
fn index(&self, index: usize) -> &Self::Output { | ||
self.scope.vars.imp_push_get_ref(Var { | ||
scope: self.scope, | ||
var_vec: self, | ||
index, | ||
}) | ||
} | ||
} | ||
|
||
/// # Expr | ||
struct Expr<'a> { | ||
scope: &'a Scope<'a>, | ||
terms: Vec<&'a Term<'a>>, | ||
} | ||
|
||
impl<'a> Display for Expr<'a> { | ||
fn fmt(&self, f: &mut Formatter<'_>) -> Result { | ||
let mut terms = self.terms.iter(); | ||
if let Some(term) = terms.next() { | ||
write!(f, "{}", term)?; | ||
for term in terms { | ||
write!(f, " + {}", term)?; | ||
} | ||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl<'a> Add<&'a Term<'a>> for &'a Expr<'a> { | ||
type Output = &'a Expr<'a>; | ||
|
||
fn add(self, rhs: &'a Term<'a>) -> Self::Output { | ||
assert!(self.scope.same_scope_as(rhs.scope)); | ||
|
||
let mut terms = self.terms.clone(); | ||
terms.push(rhs); | ||
self.scope.exprs.imp_push_get_ref(Expr { | ||
scope: self.scope, | ||
terms, | ||
}) | ||
} | ||
} | ||
|
||
/// # Term | ||
#[derive(Clone, Copy)] | ||
struct Term<'a> { | ||
scope: &'a Scope<'a>, | ||
coef: i64, | ||
var: Var<'a>, | ||
} | ||
|
||
impl<'a> Display for Term<'a> { | ||
fn fmt(&self, f: &mut Formatter<'_>) -> Result { | ||
write!(f, "{}.{}", self.coef, self.var) | ||
} | ||
} | ||
|
||
impl<'a> Add<&'a Term<'a>> for &'a Term<'a> { | ||
type Output = &'a Expr<'a>; | ||
|
||
fn add(self, rhs: &'a Term<'a>) -> Self::Output { | ||
assert!(self.scope.same_scope_as(rhs.scope)); | ||
|
||
self.scope.exprs.imp_push_get_ref(Expr { | ||
scope: self.scope, | ||
terms: vec![self, rhs], | ||
}) | ||
} | ||
} | ||
|
||
/// # Var | ||
#[derive(Clone, Copy)] | ||
struct Var<'a> { | ||
scope: &'a Scope<'a>, | ||
var_vec: &'a Vector<'a>, | ||
index: usize, | ||
} | ||
|
||
impl<'a> Display for Var<'a> { | ||
fn fmt(&self, f: &mut Formatter<'_>) -> Result { | ||
write!(f, "{}[{}]", self.var_vec, self.index) | ||
} | ||
} | ||
|
||
impl<'a> Mul<Var<'a>> for i64 { | ||
type Output = &'a Term<'a>; | ||
|
||
fn mul(self, rhs: Var<'a>) -> Self::Output { | ||
rhs.scope.terms.imp_push(Term { | ||
scope: rhs.scope, | ||
coef: self, | ||
var: rhs, | ||
}); | ||
&rhs.scope.terms[rhs.scope.terms.len() - 1] | ||
} | ||
} | ||
|
||
#[allow(unused_variables)] | ||
fn main() { | ||
/// Breakdown of types | ||
fn break_down_of_types() { | ||
let scope = Scope::default(); | ||
|
||
let x: &Vector = scope.new_var_vec("x"); | ||
|
||
let x0: Var = x[0]; | ||
let x1: Var = x[1]; | ||
|
||
let t1: &Term = 3 * x[0]; | ||
let t2: &Term = 4 * x[1]; | ||
|
||
let le: &Expr = t1 + t2; // or | ||
let le: &Expr = 3 * x[0] + 4 * x[1]; | ||
} | ||
|
||
/// Challenge #1 | ||
/// x: VarVec being a symbolic vector of variables, | ||
/// we need x[i] operator to create a new value of the scalar type | ||
/// Var and return a reference to it for an arbitrary index i. | ||
fn challenge1() { | ||
let scope = Scope::default(); | ||
|
||
let x: &Vector = scope.new_var_vec("x"); | ||
|
||
let x0: Var = x[0]; | ||
let x1: Var = x[1]; | ||
} | ||
|
||
/// Challenge #2 | ||
/// It is very important to have the symbolic types Var and Term | ||
/// to implement the Copy trait to achieve the desired expressive api. | ||
fn challenge2() { | ||
let scope = Scope::default(); | ||
|
||
let x: &Vector = scope.new_var_vec("x"); | ||
|
||
let t = 42 * x[0]; | ||
let e1 = t + 3 * x[1]; | ||
let e2 = t + 2 * x[0]; | ||
} | ||
|
||
/// The Goal | ||
fn the_goal() { | ||
let scope = Scope::default(); | ||
|
||
let x = scope.new_var_vec("x"); | ||
|
||
let le = 3 * x[0] + 4 * x[1]; | ||
|
||
assert_eq!(&le.to_string(), "3.x[0] + 4.x[1]"); | ||
println!("{}", le); | ||
} | ||
|
||
break_down_of_types(); | ||
challenge1(); | ||
challenge2(); | ||
the_goal(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
use orx_imp_vec::*; | ||
use std::fmt::{Display, Formatter, Result}; | ||
use std::ops::Index; | ||
|
||
struct Vector<'a> { | ||
symbol: String, | ||
created_vars: ImpVec<Var<'a>>, | ||
} | ||
|
||
impl<'a> Vector<'a> { | ||
fn new(symbol: &str) -> Self { | ||
Self { | ||
symbol: symbol.into(), | ||
created_vars: Default::default(), | ||
} | ||
} | ||
} | ||
|
||
impl<'a> Index<usize> for &'a Vector<'a> { | ||
type Output = Var<'a>; | ||
|
||
fn index(&self, index: usize) -> &Self::Output { | ||
let var = Var { | ||
index, | ||
vector: self, | ||
}; | ||
self.created_vars.imp_push_get_ref(var) | ||
} | ||
} | ||
|
||
#[derive(Clone, Copy)] | ||
struct Var<'a> { | ||
vector: &'a Vector<'a>, | ||
index: usize, | ||
} | ||
|
||
impl<'a> Display for Var<'a> { | ||
fn fmt(&self, f: &mut Formatter<'_>) -> Result { | ||
write!(f, "{}[{}]", &self.vector.symbol, self.index) | ||
} | ||
} | ||
|
||
fn main() { | ||
let x = &Vector::new("x"); | ||
|
||
// good | ||
|
||
let x0: Var = x[0]; | ||
assert_eq!(x0.to_string(), "x[0]"); | ||
|
||
// also good | ||
|
||
let vars1: Vec<Var> = (0..1000).map(|i| x[i]).collect(); | ||
|
||
for (i, x) in vars1.iter().enumerate() { | ||
assert_eq!(x.to_string(), format!("x[{}]", i)); | ||
} | ||
|
||
// still good | ||
|
||
let vars2: Vec<&Var> = (0..1000).map(|i| &x[i]).collect(); | ||
|
||
for (i, x) in vars2.iter().enumerate() { | ||
assert_eq!(x.to_string(), format!("x[{}]", i)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
use std::fmt::{Display, Formatter, Result}; | ||
use std::{cell::UnsafeCell, ops::Index}; | ||
|
||
struct Vector<'a> { | ||
symbol: String, | ||
created_vars: UnsafeCell<Vec<Var<'a>>>, | ||
} | ||
|
||
impl<'a> Vector<'a> { | ||
fn new(symbol: &str) -> Self { | ||
Self { | ||
symbol: symbol.into(), | ||
created_vars: Default::default(), | ||
} | ||
} | ||
} | ||
|
||
impl<'a> Index<usize> for &'a Vector<'a> { | ||
type Output = Var<'a>; | ||
|
||
fn index(&self, index: usize) -> &Self::Output { | ||
let var = Var { | ||
index, | ||
vector: self, | ||
}; | ||
|
||
let cache = unsafe { &mut *self.created_vars.get() }; | ||
cache.push(var); | ||
&cache[cache.len() - 1] | ||
} | ||
} | ||
|
||
#[derive(Clone, Copy)] | ||
struct Var<'a> { | ||
vector: &'a Vector<'a>, | ||
index: usize, | ||
} | ||
|
||
impl<'a> Display for Var<'a> { | ||
fn fmt(&self, f: &mut Formatter<'_>) -> Result { | ||
write!(f, "{}[{}]", &self.vector.symbol, self.index) | ||
} | ||
} | ||
|
||
fn main() { | ||
let x = &Vector::new("x"); | ||
|
||
// good | ||
|
||
let x0: Var = x[0]; | ||
assert_eq!(x0.to_string(), "x[0]"); | ||
|
||
// also good | ||
|
||
let vars1: Vec<Var> = (0..1000).map(|i| x[i]).collect(); | ||
|
||
for (i, x) in vars1.iter().enumerate() { | ||
assert_eq!(x.to_string(), format!("x[{}]", i)); | ||
} | ||
|
||
// ¯\_(ツ)_/¯ UNDEFINED BEHAVIOR !! | ||
|
||
let vars2: Vec<&Var> = (0..1000).map(|i| &x[i]).collect(); | ||
|
||
for (i, x) in vars2.iter().enumerate() { | ||
assert_eq!(x.to_string(), format!("x[{}]", i)); | ||
} | ||
} |
Oops, something went wrong.