parent
2f29b13e7b
commit
2cdad0e0e6
@ -1,103 +1,91 @@
|
||||
use std::{
|
||||
mem,
|
||||
ops,
|
||||
hash::{Hash, Hasher,},
|
||||
collections::HashSet,
|
||||
borrow::Borrow,
|
||||
};
|
||||
use generational_arena::{
|
||||
Arena,
|
||||
Index,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Eq)]
|
||||
pub struct Bag
|
||||
type Bags = HashSet<Rule>;
|
||||
type BagRef = String;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Rule
|
||||
{
|
||||
name: String,
|
||||
contains: Vec<Index>,
|
||||
bag: BagRef,
|
||||
contains: Vec<(usize, BagRef)>,
|
||||
}
|
||||
|
||||
impl Hash for Bag {
|
||||
#[inline] fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.as_ref().hash(state)
|
||||
impl Borrow<String> for Rule
|
||||
{
|
||||
fn borrow(&self) -> &String {
|
||||
&self.bag
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PartialEq<T> for Bag
|
||||
where T: AsRef<BagRef>
|
||||
{
|
||||
fn eq(&self, other: &T) -> bool
|
||||
{
|
||||
self.as_ref() == other.as_ref()
|
||||
impl Hash for Rule {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.bag.hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl Bag
|
||||
impl Rule
|
||||
{
|
||||
pub fn new(name: String) -> Self
|
||||
#[inline] pub fn name(&self) -> &str
|
||||
{
|
||||
Self {
|
||||
name,
|
||||
contains: Vec::new(),
|
||||
}
|
||||
&self.bag[..]
|
||||
}
|
||||
pub fn push_contents(&mut self, idx: Index)
|
||||
|
||||
/// Find the rules for each inner bag within this context
|
||||
pub fn inner_rules<'a>(&'a self, hashes: &'a Bags) -> impl Iterator<Item = &'a Rule> + 'a
|
||||
{
|
||||
self.contains.push(idx)
|
||||
self.contains.iter().filter_map(move |(_, re)| hashes.get(re))
|
||||
}
|
||||
pub fn bags_in<'a>(&'a self, w: &'a Arena<Bag>) -> impl Iterator<Item = &'a BagRef> + 'a
|
||||
#[inline] pub fn new(bag: impl Into<String>, contains: impl IntoIterator<Item = (usize, String)>) -> Self
|
||||
{
|
||||
self.contains.iter().filter_map(move |x| w.get(x.clone())).map(Self::as_ref)
|
||||
return Self::new_ex(bag.into(), contains.into_iter().collect());
|
||||
}
|
||||
pub fn contains_in(&self, w: &Arena<Bag>, bag: impl AsRef<BagRef>) -> bool
|
||||
pub fn new_ex(bag: String, contains: Vec<(usize, String)>) -> Self
|
||||
{
|
||||
for x in self.bags_in(w)
|
||||
{
|
||||
if x == bag.as_ref() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
Self {bag, contains}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl AsRef<BagRef> for Bag
|
||||
{
|
||||
#[inline] fn as_ref(&self) -> &BagRef
|
||||
pub fn all_rules<'a>(&'a self, hashes: &'a Bags) -> RuleIterator<'a>
|
||||
{
|
||||
BagRef::new_unchecked(&self.name[..])
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Deref for Bag
|
||||
{
|
||||
type Target = BagRef;
|
||||
#[inline] fn deref(&self) -> &Self::Target {
|
||||
self.as_ref()
|
||||
RuleIterator
|
||||
{
|
||||
base: self.contains.iter(),
|
||||
hashes,
|
||||
held: Vec::with_capacity(self.contains.len()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
#[repr(transparent)]
|
||||
pub struct BagRef
|
||||
pub struct RuleIterator<'a>
|
||||
{
|
||||
name: str
|
||||
base: std::slice::Iter<'a, (usize, BagRef)>,
|
||||
hashes: &'a Bags,
|
||||
held: Vec<&'a Rule>,
|
||||
}
|
||||
|
||||
impl AsRef<BagRef> for BagRef
|
||||
impl<'a> Iterator for RuleIterator<'a>
|
||||
{
|
||||
#[inline] fn as_ref(&self) -> &BagRef
|
||||
type Item = &'a Rule;
|
||||
fn next(&mut self) -> Option<Self::Item>
|
||||
{
|
||||
self
|
||||
if self.held.is_empty() {
|
||||
match self.base.next() {
|
||||
Some((_, re)) => {
|
||||
self.held.push(self.hashes.get(re).unwrap());
|
||||
},
|
||||
None => return None,
|
||||
}
|
||||
}
|
||||
let ret = self.held.remove(0);
|
||||
self.held.extend(ret.inner_rules(self.hashes));
|
||||
Some(ret)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl BagRef
|
||||
{
|
||||
#[inline] fn new_unchecked<'a>(from: &'a str) -> &'a BagRef
|
||||
{
|
||||
unsafe {
|
||||
mem::transmute(from)
|
||||
}
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(self.base.len(), None)
|
||||
}
|
||||
}
|
||||
impl<'a> std::iter::FusedIterator for RuleIterator<'a>{}
|
||||
|
@ -1,109 +1,48 @@
|
||||
use std::{
|
||||
io::{
|
||||
self, BufRead,
|
||||
},
|
||||
sync::{
|
||||
mpsc,
|
||||
},
|
||||
thread,
|
||||
marker::*,
|
||||
collections::{HashMap, HashSet,},
|
||||
};
|
||||
use generational_arena::{
|
||||
Arena, Index,
|
||||
};
|
||||
use std::io::BufRead;
|
||||
use super::bag;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
struct Rule
|
||||
fn parse_rule(from: impl AsRef<str>) -> Option<bag::Rule>
|
||||
{
|
||||
contents: Vec<(usize, String)>,
|
||||
}
|
||||
|
||||
fn parse_rest(from: mpsc::Receiver<String>) -> HashMap<String, Rule>
|
||||
{
|
||||
let mut out = HashMap::new();
|
||||
while let Ok(line) = from.recv() {
|
||||
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
struct UnlinkedBag<'a>
|
||||
{
|
||||
name: &'a str,
|
||||
cont: Rule,
|
||||
}
|
||||
|
||||
enum MaybeLinked<'a>
|
||||
{
|
||||
Unlinked(UnlinkedBag<'a>),
|
||||
Linked(bag::Bag),
|
||||
}
|
||||
|
||||
pub fn parse<R: BufRead>(from: R) -> Result<Arena<bag::Bag>, io::Error>
|
||||
{
|
||||
let mut all_possible = HashSet::<String>::new();
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let w = thread::spawn(move || parse_rest(rx));
|
||||
let from = from.as_ref();
|
||||
let mut ps = from.split("bag");
|
||||
|
||||
macro_rules! unwrap {
|
||||
(? $opt:expr) => {
|
||||
match $opt {
|
||||
Some(v) => v,
|
||||
_ => continue,
|
||||
}
|
||||
};
|
||||
($res:expr) => {
|
||||
unwrap!(? $res.ok())
|
||||
}
|
||||
}
|
||||
for line in from.lines()
|
||||
{
|
||||
let mut line = line?;
|
||||
|
||||
let irest = {
|
||||
const SPLIT: &str = "bags contain";
|
||||
let bn = {
|
||||
let idx = unwrap!(? line.find(SPLIT));
|
||||
&line[..idx]
|
||||
let name = ps.next()?.trim();
|
||||
Some(bag::Rule::new(name, (0..).zip(ps).filter_map(|(i, s)| {
|
||||
let (n, s) = if i == 0 {
|
||||
const JUNK: &str = "s contain ";
|
||||
|
||||
let (spec, rest) = (&s[JUNK.len()..]).split_once(char::is_whitespace).unwrap();
|
||||
let n: usize = match spec {
|
||||
"no" => 0,
|
||||
x => x.parse().unwrap(),
|
||||
};
|
||||
all_possible.insert(bn.trim().to_owned());
|
||||
(n, rest.trim())
|
||||
} else {
|
||||
if s.contains(".") { return None; }
|
||||
|
||||
let s = if s.starts_with("s") {
|
||||
&s[3..]
|
||||
} else if s.starts_with(",") {
|
||||
&s[2..]
|
||||
} else {
|
||||
s
|
||||
}.trim();
|
||||
//if s.starts_with(".") { return None; }
|
||||
|
||||
let (spec, rest) = s.split_once(char::is_whitespace).unwrap();
|
||||
(spec.parse().unwrap(), rest.trim())
|
||||
};
|
||||
unwrap!(tx.send(line));
|
||||
}
|
||||
let (mut unlinked, nref) = {
|
||||
let mut ulinks = w.join().unwrap();
|
||||
let mut unlinked = Arena::with_capacity(all_possible.len());
|
||||
let mut nref = HashMap::new();
|
||||
for name in all_possible.iter()
|
||||
{
|
||||
let urule = ulinks.remove(name).unwrap();
|
||||
let idx = unlinked.insert(MaybeLinked::Unlinked(UnlinkedBag{name, cont: urule}));
|
||||
nref.insert(name, idx);
|
||||
if n < 1 {
|
||||
None
|
||||
} else {
|
||||
Some((n, s.to_owned()))
|
||||
}
|
||||
(unlinked, nref)
|
||||
};
|
||||
|
||||
let indecies: Vec<_> = unlinked.iter().map(|(i, _)| i).collect();
|
||||
for idx in indecies.into_iter()
|
||||
{
|
||||
let current = unlinked.get_mut(idx).unwrap();
|
||||
let linked = match current {
|
||||
MaybeLinked::Unlinked(UnlinkedBag{name, cont: rule}) => {
|
||||
let mut linking = bag::Bag::new(name.to_owned());
|
||||
for (_, cont) in rule.contents.iter() {
|
||||
linking.push_contents(*nref.get(cont).unwrap());
|
||||
}
|
||||
linking
|
||||
},
|
||||
_=> continue,
|
||||
};
|
||||
*current = MaybeLinked::Linked(linked);
|
||||
}
|
||||
})))
|
||||
}
|
||||
|
||||
//TODO: how tf can we convert from Arena<MaybeLinked<_>> into Arena<_>?????
|
||||
|
||||
todo!()
|
||||
pub fn parse<R: BufRead>(buf: R) -> impl Iterator<Item = bag::Rule>
|
||||
{
|
||||
buf.lines().filter_map(|x| {
|
||||
x.ok().map(parse_rule).flatten()
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in new issue