tamer: ir::asg::section: Improve iteration
`SectionsIter` was introduced to remove that responsibility from xmle writer, since that's currently being reimplemented using XIR. The existing iterator has been renamed SectionIter{ator=>} for a more idiomatic name for iterator structs, and now has a static type rather than relying on dynamic dispatch. The author of that code wasn't sure how to handle it otherwise. (Which is understandable, since we were both still getting acquainted with Rust.) There's no notable change in performance in my benchmarking. This abstraction is a bit awkward, in that it's named for object file sections, but they aren't. Further, it's coupled with the ASG via `SortableAsg` and perhaps should be generalized into a sorting routine that takes a function for sorting, so that `Sections` can be moved into xmle's packages.main
parent
b80064f59e
commit
1fa9614698
|
@ -205,7 +205,7 @@ pub use object::{
|
|||
FragmentText, IdentObject, IdentObjectData, IdentObjectState, Source,
|
||||
TransitionError, TransitionResult, UnresolvedError,
|
||||
};
|
||||
pub use section::{Section, SectionIterator, Sections};
|
||||
pub use section::{Section, SectionIter, Sections};
|
||||
|
||||
/// Default concrete ASG implementation.
|
||||
pub type DefaultAsg<O, Ix> = base::BaseAsg<O, Ix>;
|
||||
|
|
|
@ -17,6 +17,16 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Ordered sections of ASG object references.
|
||||
//!
|
||||
//! These sections are the result of an ordering operation from
|
||||
//! [`SortableAsg::sort`].
|
||||
//!
|
||||
//! [`SortableAsg::sort`]: super::SortableAsg::sort
|
||||
|
||||
use std::iter::Chain;
|
||||
use std::slice::Iter;
|
||||
|
||||
/// A section of an [object file](crate::obj).
|
||||
///
|
||||
/// Most sections will only need a `body`, but some innlude `head` and `tail`
|
||||
|
@ -64,62 +74,39 @@ impl<'a, T> Section<'a, T> {
|
|||
self.tail.push(obj)
|
||||
}
|
||||
|
||||
/// Merge the parts of a `Section` into one [`SectionIterator`]
|
||||
///
|
||||
/// The `Section` internals need to be iterated as a group so we needed to
|
||||
/// create a custom iterator, [`SectionIterator`] to do this for us. This
|
||||
/// method allows us to access the iterator.
|
||||
///
|
||||
/// ```
|
||||
/// use tamer::ir::asg::{IdentObject, Section};
|
||||
/// use tamer::sym::{DefaultPkgInterner, Interner};
|
||||
///
|
||||
/// let interner = DefaultPkgInterner::new();
|
||||
/// let mut section = Section::new();
|
||||
/// let obj = IdentObject::Missing(interner.intern("ident"));
|
||||
/// let expect = vec![&obj, &obj, &obj];
|
||||
///
|
||||
/// section.push_head(&obj);
|
||||
/// section.push_body(&obj);
|
||||
/// section.push_tail(&obj);
|
||||
/// let section_iter = section.iter();
|
||||
///
|
||||
/// for object in section_iter {
|
||||
/// assert_eq!(&obj, object);
|
||||
/// }
|
||||
/// ```
|
||||
pub fn iter(&self) -> SectionIterator<T> {
|
||||
SectionIterator {
|
||||
inner: Box::new(
|
||||
self.head
|
||||
.iter()
|
||||
.chain(self.body.iter())
|
||||
.chain(self.tail.iter())
|
||||
.copied(),
|
||||
),
|
||||
}
|
||||
/// Construct a new iterator visiting each head, body, and tail object
|
||||
/// in order.
|
||||
pub fn iter(&self) -> SectionIter<T> {
|
||||
SectionIter(
|
||||
self.head
|
||||
.iter()
|
||||
.chain(self.body.iter())
|
||||
.chain(self.tail.iter()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper for an Iterator
|
||||
/// Iterator over the head, body, and tail of a [`Section`].
|
||||
///
|
||||
/// This allows us to iterate over all parts of a [`Section`].
|
||||
pub struct SectionIterator<'a, T> {
|
||||
inner: Box<dyn Iterator<Item = &'a T> + 'a>,
|
||||
}
|
||||
/// This iterator should be created with [`Section::iter`].
|
||||
///
|
||||
/// This hides the complex iterator type from callers.
|
||||
pub struct SectionIter<'a, T>(
|
||||
Chain<Chain<Iter<'a, &'a T>, Iter<'a, &'a T>>, Iter<'a, &'a T>>,
|
||||
);
|
||||
|
||||
impl<'a, T> Iterator for SectionIterator<'a, T> {
|
||||
impl<'a, T> Iterator for SectionIter<'a, T> {
|
||||
type Item = &'a T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.inner.next()
|
||||
self.0.next().map(|x| *x)
|
||||
}
|
||||
}
|
||||
|
||||
/// Sections that need to be written to a buffer
|
||||
/// ASG objects organized into logical sections.
|
||||
///
|
||||
/// All the properties are public [`Section`] objects and will be accessed
|
||||
/// directly by the the objects interacting with them.
|
||||
/// These sections may not necessarily correspond directly to sections of an
|
||||
/// [object file](crate::obj).
|
||||
#[derive(Debug, Default, PartialEq)]
|
||||
pub struct Sections<'a, T> {
|
||||
pub map: Section<'a, T>,
|
||||
|
@ -148,6 +135,56 @@ impl<'a, T> Sections<'a, T> {
|
|||
rater: Section::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct an iterator over each of the individual sections in
|
||||
/// arbitrary order.
|
||||
///
|
||||
/// Each individual section is ordered as stated in [`Section::iter`],
|
||||
/// but you should not rely on the order that the sections themselves
|
||||
/// appear in;
|
||||
/// they may change or be combined in the future.
|
||||
/// At the time of writing,
|
||||
/// they are chained in the same order in which they are defined
|
||||
/// on the [`Sections`] struct.
|
||||
pub fn iter_all(&self) -> SectionsIter<T> {
|
||||
SectionsIter(
|
||||
self.map
|
||||
.iter()
|
||||
.chain(self.retmap.iter())
|
||||
.chain(self.meta.iter())
|
||||
.chain(self.worksheet.iter())
|
||||
.chain(self.params.iter())
|
||||
.chain(self.types.iter())
|
||||
.chain(self.funcs.iter())
|
||||
.chain(self.consts.iter())
|
||||
.chain(self.rater.iter()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Compose the chained iterator type for [`SectionsIter`].
|
||||
// This could be further abstracted away,
|
||||
// but it's likely that `Sections` will be simplified in the future.
|
||||
type SIter<'a, T> = SectionIter<'a, T>;
|
||||
type CSIter1<'a, T, L> = Chain<L, SIter<'a, T>>;
|
||||
type CSIter2<'a, T, L> = CSIter1<'a, T, CSIter1<'a, T, L>>;
|
||||
type CSIter4<'a, T, L> = CSIter2<'a, T, CSIter2<'a, T, L>>;
|
||||
type CSIter8<'a, T, L> = CSIter4<'a, T, CSIter4<'a, T, L>>;
|
||||
type SIter9<'a, T> = CSIter8<'a, T, SIter<'a, T>>;
|
||||
|
||||
/// Iterator over each of the sections.
|
||||
///
|
||||
/// This iterator should be created with [`Sections::iter_all`].
|
||||
///
|
||||
/// This hides the complex iterator type from callers.
|
||||
pub struct SectionsIter<'a, T>(SIter9<'a, T>);
|
||||
|
||||
impl<'a, T> Iterator for SectionsIter<'a, T> {
|
||||
type Item = &'a T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.0.next()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -262,4 +299,30 @@ mod test {
|
|||
|
||||
assert_eq!(expect, collection);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sections_iter_all() {
|
||||
let mut sections = Sections::new();
|
||||
|
||||
let objs = (0..=10)
|
||||
.map(|i| IdentObject::<u16>::Missing(i.to_string().into()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
sections.map.head.push(&objs[0]);
|
||||
sections.map.body.push(&objs[1]);
|
||||
sections.map.tail.push(&objs[2]);
|
||||
sections.retmap.body.push(&objs[3]);
|
||||
sections.meta.body.push(&objs[4]);
|
||||
sections.worksheet.body.push(&objs[5]);
|
||||
sections.params.body.push(&objs[6]);
|
||||
sections.types.body.push(&objs[7]);
|
||||
sections.funcs.body.push(&objs[8]);
|
||||
sections.consts.body.push(&objs[9]);
|
||||
sections.rater.body.push(&objs[10]);
|
||||
|
||||
assert_eq!(
|
||||
sections.iter_all().collect::<Vec<_>>(),
|
||||
objs.iter().collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
use super::writer::{Result, WriterError};
|
||||
use crate::global;
|
||||
use crate::ir::asg::{
|
||||
IdentKind, IdentObject, IdentObjectData, SectionIterator, Sections,
|
||||
IdentKind, IdentObject, IdentObjectData, SectionIter, Sections,
|
||||
};
|
||||
use crate::sym::{GlobalSymbolResolve, ProgSymbolId, SymbolId};
|
||||
use fxhash::FxHashSet;
|
||||
|
@ -202,16 +202,7 @@ impl<W: Write> XmleWriter<W> {
|
|||
sections: &Sections<T>,
|
||||
relroot: &str,
|
||||
) -> Result<&mut XmleWriter<W>> {
|
||||
let all = sections
|
||||
.meta
|
||||
.iter()
|
||||
.chain(sections.map.iter())
|
||||
.chain(sections.retmap.iter())
|
||||
.chain(sections.worksheet.iter())
|
||||
.chain(sections.params.iter())
|
||||
.chain(sections.types.iter())
|
||||
.chain(sections.funcs.iter())
|
||||
.chain(sections.rater.iter());
|
||||
let all = sections.iter_all();
|
||||
|
||||
for obj in all {
|
||||
let ident = obj
|
||||
|
@ -352,7 +343,7 @@ impl<W: Write> XmleWriter<W> {
|
|||
/// `writer`'s 'write_event`.
|
||||
fn write_section<T: IdentObjectData<Ix>>(
|
||||
&mut self,
|
||||
idents: SectionIterator<T>,
|
||||
idents: SectionIter<T>,
|
||||
) -> Result<&mut XmleWriter<W>> {
|
||||
for obj in idents {
|
||||
let ident = obj
|
||||
|
|
Loading…
Reference in New Issue