Skip to content

Commit

Permalink
Merge pull request #33 from orxfun/imp_push_get_ref
Browse files Browse the repository at this point in the history
`imp_push_get_ref` is implemented
  • Loading branch information
orxfun authored Oct 4, 2024
2 parents 5232065 + 306a00d commit 1a32291
Show file tree
Hide file tree
Showing 6 changed files with 378 additions and 4 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[package]
name = "orx-imp-vec"
version = "2.7.0"
version = "2.8.0"
edition = "2021"
authors = ["orxfun <orx.ugur.arikan@gmail.com>"]
description = "`ImpVec`, stands for immutable push vector 👿, is a data structure which allows appending elements with a shared reference."
description = "`ImpVec` stands for immutable push vector 👿, it is a data structure which allows appending elements with a shared reference."
license = "MIT"
repository = "https://github.com/orxfun/orx-imp-vec/"
keywords = ["vec", "pinned", "bag", "container", "split"]
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![orx-imp-vec crate](https://img.shields.io/crates/v/orx-imp-vec.svg)](https://crates.io/crates/orx-imp-vec)
[![orx-imp-vec documentation](https://docs.rs/orx-imp-vec/badge.svg)](https://docs.rs/orx-imp-vec)

`ImpVec`, stands for immutable push vector 👿, is a data structure which allows appending elements with a shared reference.
`ImpVec` stands for immutable push vector 👿, it is a data structure which allows appending elements with a shared reference.

Specifically, it extends vector capabilities with the following two methods:
* [`fn imp_push(&self, value: T)`](https://docs.rs/orx-imp-vec/latest/orx_imp_vec/struct.ImpVec.html#method.imp_push)
Expand Down Expand Up @@ -196,6 +196,9 @@ assert_eq!(

</details>

You may find another demonstration where an `ImpVec` mimics a scope in the [system_of_linear_inequalities.rs](https://github.com/orxfun/orx-imp-vec/blob/main/examples/system_of_linear_inequalities.rs) example.

Finally, you may find the initial motivation of this crate and the `ImpVec` type in [imp-vec-motivation](https://orxfun.github.io/orxfun-notes/#/imp-vec-motivation-2024-10-03) article.

## Safety

Expand Down
207 changes: 207 additions & 0 deletions examples/system_of_linear_inequalities.rs
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();
}
66 changes: 66 additions & 0 deletions examples/vector_var_imp_vec.rs
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));
}
}
68 changes: 68 additions & 0 deletions examples/vector_var_unsafe_cell_vec.rs
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));
}
}
Loading

0 comments on commit 1a32291

Please sign in to comment.