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
use crate::Id;
use std::collections::{HashMap, HashSet};
/// Simple HashMap-based name generator that generates new names for each
/// prefix.
#[derive(Clone, Debug)]
pub struct NameGenerator {
name_hash: HashMap<Id, i64>,
generated_names: HashSet<Id>,
}
impl NameGenerator {
/// Create a NameGenerator where `names` are already defined so that this generator
/// will never generate those names.
pub fn with_prev_defined_names(names: HashSet<Id>) -> Self {
NameGenerator {
generated_names: names,
name_hash: HashMap::default(),
}
}
/// Add generated names
pub fn add_names(&mut self, names: HashSet<Id>) {
self.generated_names.extend(names)
}
/// Returns a new String that starts with `prefix`.
/// For example:
/// ```
/// namegen.gen_name("seq"); // Generates "seq0"
/// namegen.gen_name("seq"); // Generates "seq1"
/// ```
pub fn gen_name<S>(&mut self, prefix: S) -> Id
where
S: Into<Id>,
{
let mut cur_prefix: Id = prefix.into();
loop {
// Insert default value for this prefix if there is no entry.
let count = self
.name_hash
.entry(cur_prefix)
.and_modify(|v| *v += 1)
.or_insert(-1);
let name = if *count == -1 {
cur_prefix
} else {
Id::from(cur_prefix.to_string() + &count.to_string())
};
// If we've not generated this name before, return it.
if !self.generated_names.contains(&name) {
self.generated_names.insert(name);
return name;
}
// If the name was generated before, use the current name as the prefix.
cur_prefix = name;
}
}
}