Skip to content

Commit

Permalink
Use CowArray to keep atoms inside Expression
Browse files Browse the repository at this point in the history
  • Loading branch information
vsbogd committed Nov 13, 2024
1 parent 631a41a commit d9b2649
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 19 deletions.
34 changes: 17 additions & 17 deletions lib/src/atom/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ use std::any::Any;
use std::fmt::{Display, Debug};
use std::convert::TryFrom;

use crate::common::collections::ImmutableString;
use crate::common::collections::{ImmutableString, CowArray};

// Symbol atom

Expand Down Expand Up @@ -152,14 +152,14 @@ impl Display for SymbolAtom {
/// An expression atom structure.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ExpressionAtom {
children: Vec<Atom>,
children: CowArray<Atom>,
}

impl ExpressionAtom {
/// Constructs new expression from vector of sub-atoms. Not intended to be
/// used directly, use [Atom::expr] instead.
#[doc(hidden)]
pub(crate) fn new(children: Vec<Atom>) -> Self {
pub(crate) fn new(children: CowArray<Atom>) -> Self {
Self{ children }
}

Expand All @@ -170,17 +170,17 @@ impl ExpressionAtom {

/// Returns a reference to a vector of sub-atoms.
pub fn children(&self) -> &[Atom] {
&self.children
self.children.as_slice()
}

/// Returns a mutable reference to a vector of sub-atoms.
pub fn children_mut(&mut self) -> &mut [Atom] {
&mut self.children
self.children.as_slice_mut()
}

/// Converts into a vector of sub-atoms.
pub fn into_children(self) -> Vec<Atom> {
self.children
self.children.into()
}
}

Expand Down Expand Up @@ -837,7 +837,7 @@ impl Atom {
/// assert_eq!(expr, same_expr);
/// assert_ne!(expr, other_expr);
/// ```
pub fn expr<T: Into<Vec<Atom>>>(children: T) -> Self {
pub fn expr<T: Into<CowArray<Atom>>>(children: T) -> Self {
Self::Expression(ExpressionAtom::new(children.into()))
}

Expand Down Expand Up @@ -1093,8 +1093,8 @@ mod test {
}

#[inline]
fn expression(children: Vec<Atom>) -> Atom {
Atom::Expression(ExpressionAtom{ children })
fn expression<const N: usize>(children: [Atom; N]) -> Atom {
Atom::Expression(ExpressionAtom::new(CowArray::Allocated(Box::new(children))))
}

#[inline]
Expand Down Expand Up @@ -1175,15 +1175,15 @@ mod test {
#[test]
fn test_expr_expression() {
assert_eq!(expr!("=" ("fact" n) ("*" n ("-" n "1"))),
expression(vec![symbol("="), expression(vec![symbol("fact"), variable("n")]),
expression(vec![symbol("*"), variable("n"),
expression(vec![symbol("-"), variable("n"), symbol("1") ]) ]) ]));
expression([symbol("="), expression([symbol("fact"), variable("n")]),
expression([symbol("*"), variable("n"),
expression([symbol("-"), variable("n"), symbol("1") ]) ]) ]));
assert_eq!(expr!("=" n {[1, 2, 3]}),
expression(vec![symbol("="), variable("n"), value([1, 2, 3])]));
expression([symbol("="), variable("n"), value([1, 2, 3])]));
assert_eq!(expr!("=" {6} ("fact" n)),
expression(vec![symbol("="), value(6), expression(vec![symbol("fact"), variable("n")])]));
expression([symbol("="), value(6), expression([symbol("fact"), variable("n")])]));
assert_eq!(expr!({TestMulX(3)} {TestInteger(6)}),
expression(vec![grounded(TestMulX(3)), grounded(TestInteger(6))]));
expression([grounded(TestMulX(3)), grounded(TestInteger(6))]));
}

#[test]
Expand Down Expand Up @@ -1239,8 +1239,8 @@ mod test {
assert_eq!(Atom::gnd(TestMulX(3)).clone(), grounded(TestMulX(3)));
assert_eq!(Atom::expr([Atom::sym("="), Atom::value(6),
Atom::expr([Atom::sym("fact"), Atom::var("n")])]).clone(),
expression(vec![symbol("="), value(6),
expression(vec![symbol("fact"), variable("n")])]));
expression([symbol("="), value(6),
expression([symbol("fact"), variable("n")])]));
}

#[test]
Expand Down
91 changes: 91 additions & 0 deletions lib/src/common/collections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,97 @@ impl From<String> for ImmutableString {
}
}

#[derive(Debug, Clone)]
pub enum CowArray<T: 'static> {
Allocated(Box<[T]>),
Literal(&'static [T]),
}

impl<T: 'static> CowArray<T> {

pub fn new() -> Self {
Self::Literal(&[])
}

pub fn as_slice(&self) -> &[T] {
match self {
Self::Allocated(array) => &*array,
Self::Literal(array) => array,
}
}

pub fn as_slice_mut(&mut self) -> &mut [T] where T: Clone {
match self {
Self::Allocated(array) => &mut *array,
Self::Literal(array) => {
*self = Self::Allocated((*array).into());
self.as_slice_mut()
}
}
}

pub fn len(&self) -> usize {
self.as_slice().len()
}

pub fn iter(&self) -> impl Iterator<Item=&T> {
self.as_slice().iter()
}
}

impl<T: PartialEq> PartialEq for CowArray<T> {
fn eq(&self, other: &Self) -> bool {
self.as_slice() == other.as_slice()
}
}

impl<T: Eq> Eq for CowArray<T> {}

impl<T: Display> Display for CowArray<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[")
.and_then(|_| self.as_slice().iter().take(1).fold(Ok(()),
|res, atom| res.and_then(|_| write!(f, "{}", atom))))
.and_then(|_| self.as_slice().iter().skip(1).fold(Ok(()),
|res, atom| res.and_then(|_| write!(f, " {}", atom))))
.and_then(|_| write!(f, "]"))
}
}

impl<T: 'static> From<&'static [T]> for CowArray<T> {
fn from(a: &'static [T]) -> Self {
CowArray::Literal(a)
}
}

impl<T, const N: usize> From<[T; N]> for CowArray<T> {
fn from(a: [T; N]) -> Self {
CowArray::Allocated(Box::new(a))
}
}

impl<T> From<Vec<T>> for CowArray<T> {
fn from(v: Vec<T>) -> Self {
CowArray::Allocated(v.into_boxed_slice())
}
}

impl<T: Clone> Into<Vec<T>> for CowArray<T> {
fn into(self) -> Vec<T> {
match self {
Self::Allocated(array) => array.into(),
Self::Literal(array) => array.into(),
}
}
}

impl<'a, T> Into<&'a [T]> for &'a CowArray<T> {
fn into(self) -> &'a [T] {
self.as_slice()
}
}


#[cfg(test)]
mod test {
use super::*;
Expand Down
5 changes: 3 additions & 2 deletions lib/src/metta/interpreter_minimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::space::*;
use crate::metta::*;
use crate::metta::types::*;
use crate::metta::runner::stdlib_minimal::IfEqualOp;
use crate::common::collections::CowArray;

use std::fmt::{Debug, Display, Formatter};
use std::convert::TryFrom;
Expand Down Expand Up @@ -679,11 +680,11 @@ fn collapse_bind_ret(stack: Rc<RefCell<Stack>>, atom: Atom, bindings: Bindings)
let Stack{ prev: _, atom: collapse, ret: _, finished: _, vars: _ } = stack_ref;
match atom_as_slice_mut(collapse) {
Some([_op, Atom::Expression(finished_placeholder), _bindings]) => {
let mut finished = ExpressionAtom::new(Vec::new());
let mut finished = ExpressionAtom::new(CowArray::new());
std::mem::swap(&mut finished, finished_placeholder);
let mut finished = finished.into_children();
finished.push(atom_bindings_into_atom(nested, bindings));
std::mem::swap(&mut ExpressionAtom::new(finished), finished_placeholder);
std::mem::swap(&mut ExpressionAtom::new(finished.into()), finished_placeholder);
},
_ => panic!("Unexpected state"),
};
Expand Down

0 comments on commit d9b2649

Please sign in to comment.