pub mod idx {
new! {
Client,
map: Clients,
btree set: ClientSet,
}
new! {
File,
map: Files,
btree set: FileSet,
}
}
use idx::*;
pub struct ClientInfo {
pub name: alloc::string::String,
pub files: FileSet,
}
pub struct FileInfo {
pub name: alloc::string::String,
pub clients: ClientSet,
}
impl FileInfo {
pub fn new<S, I>(name: S, clients: I) -> Self
where
S: Into<alloc::string::String>,
I: core::iter::IntoIterator<Item = Client>,
{
FileInfo {
name: name.into(),
clients: clients.into_iter().collect(),
}
}
}
impl core::ops::Index<Client> for Data {
type Output = ClientInfo;
fn index(&self, client: Client) -> &ClientInfo {
&self.clients[client]
}
}
pub struct Data {
pub clients: Clients<ClientInfo>,
pub files: Files<FileInfo>,
}
impl Data {
pub fn new() -> Data {
Data {
clients: Clients::with_capacity(103),
files: Files::with_capacity(103),
}
}
pub fn add_client<S: Into<alloc::string::String>>(&mut self, name: S) -> Client {
let name = name.into();
for (client, info) in self.clients.index_iter() {
if info.name == name {
return client;
}
}
self.clients.push(ClientInfo {
name,
files: FileSet::new(),
})
}
pub fn add_file(&mut self, file: FileInfo) -> File {
let idx = self.files.push(file);
let file = &self.files[idx];
for client in &file.clients {
let is_new = self.clients[*client].files.insert(idx);
debug_assert! { is_new }
}
idx
}
pub fn get_file(&mut self, file: File) -> &FileInfo {
&self.files[file]
}
pub fn add_client_to_file(&mut self, client: Client, file: File) {
let is_new = self.files[file].clients.insert(client);
debug_assert! { is_new }
let is_new = self.clients[client].files.insert(file);
debug_assert! { is_new }
}
pub fn client_clusters(&self) -> alloc::vec::Vec<(ClientSet, FileSet)> {
let mut res: alloc::vec::Vec<(ClientSet, FileSet)> = alloc::vec![];
macro_rules! is_known {
($file:expr) => {
res.iter().any(|(_, files)| files.contains(&$file))
};
}
'all_files: for (file, file_info) in self.files.index_iter() {
if is_known!(file) {
continue 'all_files;
}
let (mut clients, mut files) = (ClientSet::new(), FileSet::new());
files.insert(file);
let mut to_dos = alloc::vec![&file_info.clients];
while let Some(to_do) = to_dos.pop() {
for client in to_do {
let is_new = clients.insert(*client);
if is_new {
for file in &self.clients[*client].files {
let is_new = files.insert(*file);
if is_new {
to_dos.push(&self.files[*file].clients)
}
}
}
}
}
res.push((clients, files))
}
res
}
}
#[test]
fn run() {
let mut data = Data::new();
let c_1 = data.add_client("client 1");
let c_2 = data.add_client("client 2");
let c_3 = data.add_client("client 3");
let c_4 = data.add_client("client 4");
let f_1 = data.add_file(FileInfo::new("file 1", alloc::vec![c_1, c_2]));
let f_2 = data.add_file(FileInfo::new("file 2", alloc::vec![c_3]));
let f_3 = data.add_file(FileInfo::new("file 3", alloc::vec![c_2]));
let f_4 = data.add_file(FileInfo::new("file 4", alloc::vec![c_4]));
let classes = data.client_clusters();
let expected: alloc::vec::Vec<(ClientSet, FileSet)> = alloc::vec![
(
alloc::vec![c_1, c_2].into_iter().collect(),
alloc::vec![f_1, f_3].into_iter().collect(),
),
(
alloc::vec![c_3].into_iter().collect(),
alloc::vec![f_2].into_iter().collect(),
),
(
alloc::vec![c_4].into_iter().collect(),
alloc::vec![f_4].into_iter().collect(),
),
];
assert_eq! { classes, expected }
data.add_client_to_file(c_3, f_3);
let classes = data.client_clusters();
let expected: alloc::vec::Vec<(ClientSet, FileSet)> = alloc::vec![
(
alloc::vec![c_1, c_2, c_3].into_iter().collect(),
alloc::vec![f_1, f_2, f_3].into_iter().collect(),
),
(
alloc::vec![c_4].into_iter().collect(),
alloc::vec![f_4].into_iter().collect(),
),
];
assert_eq! { classes, expected }
}