ms_pdb/utils/
iter.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//! Iterator utilities

use std::ops::Range;

/// Allows iterators to report the remaining, unparsed bytes within an iterator.
///
/// This is for iterators that parse items from `&[u8]` buffers or similar.
pub trait HasRestLen {
    /// Returns the number of bytes (or elements, abstractly) that have not yet been parsed by this
    /// iterator.
    fn rest_len(&self) -> usize;
}

/// An iterator adapter which reports the byte ranges of the items that are iterated by the
/// underlying iterator. The underlying iterator must implement `HasRestLen`.
pub struct IterWithRange<I> {
    original_len: usize,
    inner: I,
}

impl<I> IterWithRange<I> {
    /// The number of items (usually bytes) that were present in the inner iterator when this
    /// `IterWithRange` was created. This value allows us to convert the "bytes remaining" value
    /// (`rest_len()`, which is what the inner iterator operates directly on) to an offset from the
    /// beginning of a buffer.
    pub fn original_len(&self) -> usize {
        self.original_len
    }

    /// Gets access to the inner iterator.
    pub fn inner(&self) -> &I {
        &self.inner
    }

    /// Gets mutable access to the inner iterator.
    ///
    /// Be warned!  If you modify this iterator, make sure you don't break its relationship with
    /// the `original_len` value.  Iterating items from it is fine, because that should never
    /// break the relationship with `original_len`.
    ///
    /// What would break it would be replacing the inner iterator with one that has a length that
    /// is greater than `original_len`.
    pub fn inner_mut(&mut self) -> &mut I {
        &mut self.inner
    }

    /// The current position in the iteration range.
    #[inline(always)]
    pub fn pos(&self) -> usize
    where
        I: HasRestLen,
    {
        self.original_len - self.inner.rest_len()
    }
}

impl<I: Iterator> Iterator for IterWithRange<I>
where
    I: HasRestLen,
{
    type Item = (Range<usize>, I::Item);

    fn next(&mut self) -> Option<Self::Item> {
        let pos_before = self.pos();
        let item = self.inner.next()?;
        let pos_after = self.pos();
        Some((pos_before..pos_after, item))
    }
}

/// An extension trait for iterators that converts an `Iterator` into an `IterWithRange`.
/// Use `foo.with_ranges()` to convert (augment) the iterator.
pub trait IteratorWithRangesExt: Sized {
    /// Augments this iterator with information about the byte range of each underlying item.
    fn with_ranges(self) -> IterWithRange<Self>;
}

impl<I> IteratorWithRangesExt for I
where
    I: Iterator + HasRestLen,
{
    fn with_ranges(self) -> IterWithRange<Self> {
        IterWithRange {
            original_len: self.rest_len(),
            inner: self,
        }
    }
}

use std::collections::BTreeMap;

/// Reads a slice of items and groups them using a function over the items.
pub fn group_by<'a, T, F, K>(s: &'a [T], f: F) -> BTreeMap<K, Vec<&'a T>>
where
    F: Fn(&T) -> K,
    K: Ord + Eq,
{
    let mut out: BTreeMap<K, Vec<&'a T>> = BTreeMap::new();

    for item in s.iter() {
        let key = f(item);
        if let Some(list) = out.get_mut(&key) {
            list.push(item);
        } else {
            out.insert(key, vec![item]);
        }
    }

    out
}

/// Reads a sequence of items and groups them using a function over the items.
pub fn group_by_iter_ref<'a, T, F, I, K>(iter: I, f: F) -> BTreeMap<K, Vec<&'a T>>
where
    I: Iterator<Item = &'a T>,
    F: Fn(&T) -> K,
    K: Ord + Eq,
{
    let mut out: BTreeMap<K, Vec<&'a T>> = BTreeMap::new();

    for item in iter {
        let key = f(item);
        if let Some(list) = out.get_mut(&key) {
            list.push(item);
        } else {
            out.insert(key, vec![item]);
        }
    }

    out
}

/// Reads a sequence of items and groups them using a function over the items.
pub fn group_by_iter<I, F, K>(iter: I, f: F) -> BTreeMap<K, Vec<I::Item>>
where
    I: Iterator,
    F: Fn(&I::Item) -> K,
    K: Ord + Eq,
{
    let mut out: BTreeMap<K, Vec<I::Item>> = BTreeMap::new();

    for item in iter {
        let key = f(&item);
        if let Some(list) = out.get_mut(&key) {
            list.push(item);
        } else {
            out.insert(key, vec![item]);
        }
    }

    out
}