1
#![forbid(unsafe_code)]
2

            
3
use std::fmt;
4

            
5
use merc_collections::Block;
6
use merc_collections::BlockIndex;
7
use merc_collections::BlockIter;
8
use merc_collections::BlockPartition;
9
use merc_lts::StateIndex;
10

            
11
use crate::Partition;
12

            
13
/// A partition that explicitly stores a list of blocks and their indexing into
14
/// the list of elements. Similar to [super::BlockPartition] but without taking
15
/// the stability of individual elements into account.
16
#[derive(Debug)]
17
pub struct MarkedBlockPartition {
18
    partition: BlockPartition<bool>,
19
}
20

            
21
impl MarkedBlockPartition {
22
    /// Create an initial partition where all the states are in a single block
23
    /// 0. And all the elements in the block are marked.
24
701
    pub fn new(num_of_elements: usize) -> Self {
25
701
        Self {
26
701
            partition: BlockPartition::new(num_of_elements),
27
701
        }
28
701
    }
29

            
30
    /// Marks the given block as stable
31
6441
    pub fn mark_block_stable(&mut self, block_index: BlockIndex) {
32
6441
        *self.partition.block_annotation(block_index) = true;
33
6441
    }
34

            
35
    /// Return a reference to the given block.
36
16791
    pub fn block(&self, block_index: BlockIndex) -> &Block<bool> {
37
16791
        self.partition.block(block_index)
38
16791
    }
39

            
40
    /// Splits a block into two blocks according to the given predicate. If
41
    /// a split occurs both blocks are marked as unstable.
42
    ///
43
    /// If the predicate holds for all or none of the elements, no split occurs.
44
3474651
    pub fn split_block(
45
3474651
        &mut self,
46
3474651
        block_index: BlockIndex,
47
3474651
        predicate: impl Fn(StateIndex) -> bool,
48
3474651
    ) -> Option<BlockIndex> {
49
3474651
        let result = self
50
3474651
            .partition
51
12294534
            .split_block(block_index, |element| predicate(StateIndex::new(element)));
52

            
53
3474651
        if let Some(new_block_index) = result {
54
4687
            *self.partition.block_annotation(block_index) = false;
55
4687
            *self.partition.block_annotation(new_block_index) = false;
56
3469964
        }
57

            
58
3474651
        result
59
3474651
    }
60

            
61
    /// Returns the number of blocks in the partition.
62
64514
    pub fn num_of_blocks(&self) -> usize {
63
64514
        self.partition.num_of_blocks()
64
64514
    }
65

            
66
    /// Returns an iterator over the elements of a given block.
67
1490348
    pub fn iter_block(&self, block_index: BlockIndex) -> BlockIter<'_> {
68
1490348
        self.partition.iter_block(block_index)
69
1490348
    }
70

            
71
    /// Returns an iterator over all blocks in the partition.
72
    pub fn iter(&self) -> impl Iterator<Item = &Block<bool>> {
73
        self.partition.iter()
74
    }
75

            
76
    /// Returns an iterator over all blocks in the partition.
77
    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Block<bool>> {
78
        self.partition.iter_mut()
79
    }
80
}
81

            
82
impl fmt::Display for MarkedBlockPartition {
83
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84
        write!(f, "{}", self.partition)
85
    }
86
}
87

            
88
impl Partition for MarkedBlockPartition {
89
66836
    fn block_number(&self, state_index: StateIndex) -> BlockIndex {
90
        // Note that this is O(n) in the number of blocks. This could be improved
91
        // by storing a mapping from state index to block index. However, this
92
        // is only used in the comparison functions, so it is not a big issue.
93
5059095
        for block_index in 0..self.partition.num_of_blocks() {
94
14448496
            for element in self.partition.iter_block(BlockIndex::new(block_index)) {
95
14448496
                if element == *state_index {
96
66836
                    return BlockIndex::new(block_index);
97
14381660
                }
98
            }
99
        }
100

            
101
        panic!("State index {:?} not found in partition {:?}", state_index, self);
102
66836
    }
103

            
104
20964
    fn num_of_blocks(&self) -> usize {
105
20964
        self.partition.num_of_blocks()
106
20964
    }
107

            
108
    fn len(&self) -> usize {
109
        self.partition.len()
110
    }
111
}
112

            
113
#[cfg(test)]
114
mod tests {
115
    use super::*;
116

            
117
    #[test]
118
1
    fn test_simple_block_partition() {
119
1
        let mut partition = MarkedBlockPartition::new(10);
120

            
121
1
        assert_eq!(partition.num_of_blocks(), 1);
122

            
123
1
        let initial_block = BlockIndex::new(0);
124
1
        assert_eq!(partition.block(initial_block).len(), 10);
125

            
126
1
        let block_index = partition
127
10
            .split_block(BlockIndex::new(0), |state| *state < *StateIndex::new(5))
128
1
            .unwrap();
129

            
130
1
        assert_eq!(partition.num_of_blocks(), 2);
131
1
        assert_eq!(partition.block(initial_block).len(), 5);
132
1
        assert_eq!(partition.block(block_index).len(), 5);
133
1
    }
134
}