Skip to content

Commit

Permalink
Prevent cylic paths
Browse files Browse the repository at this point in the history
  • Loading branch information
AZWN committed Nov 24, 2023
1 parent ce39c44 commit 2b8d6e7
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 17 deletions.
1 change: 1 addition & 0 deletions scopegraphs-lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
prust-lib = "0.1.0"
scopegraphs-regular-expressions = {path = "../scopegraphs-regular-expressions"}

[dev-dependencies]
Expand Down
102 changes: 86 additions & 16 deletions scopegraphs-lib/src/resolve/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
pub mod topdown;

use std::{collections::HashSet, hash::Hash, sync::Arc};
use std::{collections::HashSet, fmt::Debug, hash::Hash, sync::Arc};

use prust_lib::hashmap::{empty, HashSet as TrieSet};

#[derive(Hash, PartialEq, Eq, Debug)]
enum InnerPath<'sg, SCOPE, LABEL> {
enum InnerPath<'sg, SCOPE, LABEL>
where
SCOPE: PartialEq,
{
Start {
source: &'sg SCOPE,
},
Expand All @@ -14,33 +19,98 @@ enum InnerPath<'sg, SCOPE, LABEL> {
},
}

#[derive(Hash, PartialEq, Eq, Debug, Clone)]
pub struct Path<'sg, SCOPE, LABEL>(Arc<InnerPath<'sg, SCOPE, LABEL>>);
#[derive(Clone)]
pub struct Path<'sg, SCOPE, LABEL>
where
SCOPE: PartialEq,
{
inner_path: Arc<InnerPath<'sg, SCOPE, LABEL>>,
scopes: TrieSet<&'sg SCOPE>,
}

impl<'sg, SCOPE, LABEL> PartialEq for Path<'sg, SCOPE, LABEL>
where
SCOPE: PartialEq,
LABEL: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.inner_path == other.inner_path
}
}

impl<'sg, SCOPE, LABEL> Eq for Path<'sg, SCOPE, LABEL>
where
SCOPE: Eq,
LABEL: Eq,
{
}

impl<'sg, SCOPE, LABEL> Hash for Path<'sg, SCOPE, LABEL>
where
SCOPE: PartialEq + Hash,
LABEL: Hash,
{
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.inner_path.hash(state);
}
}

impl<'sg, SCOPE, LABEL> Debug for Path<'sg, SCOPE, LABEL>
where
SCOPE: PartialEq + Debug,
LABEL: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Path")
.field("inner_path", &self.inner_path)
.finish()
}
}

#[derive(Hash, PartialEq, Eq, Debug, Clone)]
pub struct ResolvedPath<'sg, SCOPE, LABEL, DATA> {
pub struct ResolvedPath<'sg, SCOPE, LABEL, DATA>
where
SCOPE: PartialEq,
{
path: Path<'sg, SCOPE, LABEL>,
data: &'sg DATA,
}

impl<'sg, SCOPE, LABEL> Path<'sg, SCOPE, LABEL> {
impl<'sg, SCOPE, LABEL> Path<'sg, SCOPE, LABEL>
where
SCOPE: Eq + Hash,
LABEL: Eq,
{
pub fn new(source: &'sg SCOPE) -> Self {
Self(Arc::new(InnerPath::Start { source }))
Self {
inner_path: Arc::new(InnerPath::Start { source }),
scopes: empty().insert(source),
}
}

pub fn target(&self) -> &SCOPE {
match self.0.as_ref() {
match self.inner_path.as_ref() {
InnerPath::Start { source } => source,
InnerPath::Step { target, .. } => target,
}
}

pub fn step(&self, label: LABEL, target: &'sg SCOPE) -> Self {
Self(Arc::new(InnerPath::Step {
prefix: Self(self.0.clone()),
label,
target,
}))
pub fn step(&self, label: LABEL, target: &'sg SCOPE) -> Option<Self> {
if self.scopes.search(&target) {
None
} else {
Some(Self {
inner_path: Arc::new(InnerPath::Step {
prefix: Self {
inner_path: self.inner_path.clone(),
scopes: self.scopes.clone(),
},
label,
target,
}),
scopes: self.scopes.insert(target),
})
}
}

pub fn resolve<DATA>(self, data: &'sg DATA) -> ResolvedPath<SCOPE, LABEL, DATA> {
Expand All @@ -53,9 +123,9 @@ impl<'sg, SCOPE, LABEL> Path<'sg, SCOPE, LABEL> {
// - we currently create a lot of new hashmaps, which is not really efficient
// - efficiency might be dependent on the name resolution (shadowing) strategy
// Perhaps we will resort to fibbonacy heaps/pairing heaps, and/or make resolution parametric in the environment type.
pub struct Env<'sg, SCOPE, LABEL, DATA>(HashSet<ResolvedPath<'sg, SCOPE, LABEL, DATA>>);
pub struct Env<'sg, SCOPE: PartialEq, LABEL, DATA>(HashSet<ResolvedPath<'sg, SCOPE, LABEL, DATA>>);

impl<'sg, SCOPE, LABEL, DATA> IntoIterator for Env<'sg, SCOPE, LABEL, DATA> {
impl<'sg, SCOPE: PartialEq, LABEL, DATA> IntoIterator for Env<'sg, SCOPE, LABEL, DATA> {
type Item = ResolvedPath<'sg, SCOPE, LABEL, DATA>;

type IntoIter = std::collections::hash_set::IntoIter<ResolvedPath<'sg, SCOPE, LABEL, DATA>>;
Expand Down
3 changes: 2 additions & 1 deletion scopegraphs-lib/src/resolve/topdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ where
path_wellformedness.step(label);
let mut env = Env::new();
for tgt in self.sg.get_edges(path.target(), label) {
env.merge(self.resolve_all(path_wellformedness, &path.step(*label, tgt)))
path.step(*label, tgt)
.inspect(|p| env.merge(self.resolve_all(path_wellformedness, p)));
}

env
Expand Down

0 comments on commit 2b8d6e7

Please sign in to comment.