1
#![forbid(unsafe_code)]
2

            
3
use std::fmt;
4

            
5
use merc_utilities::TagIndex;
6

            
7
/// A zero sized tag for the block.
8
pub struct BlockTag {}
9

            
10
/// The index for blocks.
11
pub type BlockIndex = TagIndex<usize, BlockTag>;
12

            
13
/// Defines a partition based on an explicit indexing of elements to their block
14
/// number.
15
/// 
16
/// Note that the assumption is that the elements are dense, and the
17
/// corresponding blocks as well.
18
#[derive(Debug)]
19
pub struct IndexedPartition {
20
    /// Stores a mapping from element index to block number.
21
    partition: Vec<BlockIndex>,
22

            
23
    /// Keeps track of the number of blocks defined.
24
    num_of_blocks: usize,
25
}
26

            
27
impl IndexedPartition {
28
    /// Create a new partition where all elements are in a single block.
29
76011
    pub fn new(num_of_elements: usize) -> IndexedPartition {
30
76011
        IndexedPartition {
31
76011
            partition: vec![BlockIndex::new(0); num_of_elements],
32
76011
            num_of_blocks: 1,
33
76011
        }
34
76011
    }
35

            
36
    /// Create a new partition with the given partitioning.
37
    pub fn with_partition(partition: Vec<BlockIndex>, num_of_blocks: usize) -> IndexedPartition {
38
        IndexedPartition {
39
            partition,
40
            num_of_blocks,
41
        }
42
    }
43

            
44
    /// Iterates over the blocks in the partition.
45
15600
    pub fn iter(&self) -> impl Iterator<Item = BlockIndex> + '_ {
46
15600
        self.partition.iter().copied()
47
15600
    }
48

            
49
    /// Sets the block number of the given element
50
    ///
51
    /// # Details
52
    ///
53
    /// This assumes that the blocks are dense, otherwise the partition overestimates the total number of blocks present returned from `len`.
54
7279878
    pub fn set_block(&mut self, element_index: usize, block_number: BlockIndex) {
55
7279878
        self.num_of_blocks = self.num_of_blocks.max(block_number.value() + 1);
56

            
57
7279878
        self.partition[element_index] = block_number;
58
7279878
    }
59

            
60
    /// Returns the block number of the given element.
61
10000
    pub fn block(&self, element_index: usize) -> BlockIndex {
62
10000
        self.partition[element_index]
63
10000
    }
64

            
65
    /// Returns the number of blocks in the partition.
66
14918
    pub fn len(&self) -> usize {
67
14918
        self.partition.len()
68
14918
    }
69

            
70
    /// Returns whether the partition is empty.
71
    pub fn is_empty(&self) -> bool {
72
        self.partition.is_empty()
73
    }
74

            
75
    /// Returns the number of blocks in the partition.
76
6464844
    pub fn num_of_blocks(&self) -> usize {
77
6464844
        self.num_of_blocks
78
6464844
    }
79

            
80
    /// Returns the underlying partition vector.
81
29470881
    pub fn partition(&self) -> &Vec<BlockIndex> {
82
29470881
        &self.partition
83
29470881
    }
84
}
85

            
86
/// Reorders the blocks of the given partition according to the given permutation.
87
pub fn reorder_partition<P>(partition: IndexedPartition, permutation: P) -> IndexedPartition
88
where
89
    P: Fn(BlockIndex) -> BlockIndex,
90
{
91
    let mut new_partition = IndexedPartition::new(partition.partition.len());
92

            
93
    for (element_index, block) in partition.iter().enumerate() {
94
        new_partition.set_block(element_index, permutation(block));
95
    }
96

            
97
    new_partition
98
}
99

            
100
impl fmt::Display for IndexedPartition {
101
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102
        write!(f, "{{ ")?;
103

            
104
        let mut first = true;
105

            
106
        for block_index in 0..self.partition.len() {
107
            // Print all elements with the same block number.
108
            let mut first_block = true;
109
            for (element_index, _) in self.iter().enumerate().filter(|(_, value)| *value == block_index) {
110
                if !first_block {
111
                    write!(f, ", ")?;
112
                } else {
113
                    if !first {
114
                        write!(f, ", ")?;
115
                    }
116

            
117
                    write!(f, "{{")?;
118
                }
119

            
120
                write!(f, "{element_index}")?;
121
                first_block = false;
122
            }
123

            
124
            if !first_block {
125
                write!(f, "}}")?;
126
                first = false;
127
            }
128
        }
129

            
130
        write!(f, " }}")
131
    }
132
}