use std::collections::{BTreeMap, HashMap};
use std::fmt::{Display, Write};
use std::hash::Hash;
mod sailed {
pub trait EncodeUtf8 {}
pub trait StrExt {}
pub trait StringExt: StrExt {}
pub trait FrequencyMap<K>: Default {
fn increment(&mut self, key: K);
}
}
impl sailed::EncodeUtf8 for char {}
impl sailed::EncodeUtf8 for &str {}
impl sailed::EncodeUtf8 for String {}
impl sailed::StrExt for str {}
impl sailed::StrExt for String {}
impl sailed::StringExt for String {}
impl<K: Ord> sailed::FrequencyMap<K> for BTreeMap<K, usize> {
fn increment(&mut self, key: K) {
self.entry(key).and_modify(|n| *n += 1).or_insert(1);
}
}
impl<K: Eq + Hash> sailed::FrequencyMap<K> for HashMap<K, usize> {
fn increment(&mut self, key: K) {
self.entry(key).and_modify(|n| *n += 1).or_insert(1);
}
}
pub trait EncodeUtf8: sailed::EncodeUtf8 {
type Buf: Default;
fn encode_utf8<'a>(&'a self, buf: &'a mut Self::Buf) -> &'a str;
}
impl EncodeUtf8 for char {
type Buf = [u8; 4];
fn encode_utf8<'a>(&'a self, buf: &'a mut Self::Buf) -> &'a str {
char::encode_utf8(*self, buf)
}
}
impl EncodeUtf8 for &str {
type Buf = ();
fn encode_utf8<'a>(&'a self, _: &'a mut Self::Buf) -> &'a str {
self
}
}
impl EncodeUtf8 for String {
type Buf = ();
fn encode_utf8<'a>(&'a self, _: &'a mut Self::Buf) -> &'a str {
self.as_str()
}
}
pub trait StrExt: sailed::StrExt {
fn fill_start(&self, fill: impl EncodeUtf8, count: usize) -> String;
fn fill_end(&self, fill: impl EncodeUtf8, count: usize) -> String;
fn center(&self, fill: impl EncodeUtf8, count: usize) -> String;
fn enclose(&self, fill_start: impl EncodeUtf8, fill_end: impl EncodeUtf8) -> String;
fn expand_tabs(&self, tab_size: usize) -> String;
fn truncate_to_chars(&self, count: usize) -> &str;
fn pad_start_to(&self, width: usize, fill: char) -> String;
fn pad_end_to(&self, width: usize, fill: char) -> String;
fn center_to(&self, width: usize, fill: char) -> String;
fn shift(&self, index: usize, count: usize, fill: impl EncodeUtf8) -> String;
fn levenshtein_distance(&self, other: &str) -> usize;
fn hamming_distance(&self, other: &str) -> Option<usize>;
fn common_prefix(&self, other: &str) -> &str;
fn common_suffix(&self, other: &str) -> &str;
fn char_frequencies<M: sailed::FrequencyMap<char>>(&self) -> M;
fn byte_frequencies<M: sailed::FrequencyMap<u8>>(&self) -> M;
fn longest_common_substring(&self, other: &str) -> &str;
fn next_char_boundary(&self, index: usize) -> usize;
fn previous_char_boundary(&self, index: usize) -> usize;
fn join<T: Display>(&self, iterable: impl IntoIterator<Item = T>) -> String;
}
impl StrExt for str {
fn fill_start(&self, fill: impl EncodeUtf8, count: usize) -> String {
let mut buf = Default::default();
let fill = fill.encode_utf8(&mut buf);
let mut string = String::with_capacity(fill.len() * count + self.len());
for _ in 0..count {
string.push_str(fill);
}
string.push_str(self);
string
}
fn fill_end(&self, fill: impl EncodeUtf8, count: usize) -> String {
let mut buf = Default::default();
let fill = fill.encode_utf8(&mut buf);
let mut string = String::with_capacity(fill.len() * count + self.len());
string.push_str(self);
for _ in 0..count {
string.push_str(fill);
}
string
}
fn center(&self, fill: impl EncodeUtf8, count: usize) -> String {
let mut buf = Default::default();
let fill = fill.encode_utf8(&mut buf);
let mut string = String::with_capacity(fill.len() * 2 * count + self.len());
for _ in 0..count {
string.push_str(fill);
}
string.push_str(self);
for _ in 0..count {
string.push_str(fill);
}
string
}
fn enclose(&self, fill_start: impl EncodeUtf8, fill_end: impl EncodeUtf8) -> String {
let (mut start_buf, mut end_buf) = (Default::default(), Default::default());
let (start, end) = (
fill_start.encode_utf8(&mut start_buf),
fill_end.encode_utf8(&mut end_buf),
);
let mut string = String::with_capacity(start.len() + self.len() + end.len());
string.push_str(start);
string.push_str(self);
string.push_str(end);
string
}
fn expand_tabs(&self, tab_size: usize) -> String {
if tab_size == 0 || self.is_empty() {
return self.to_string();
}
let mut string = String::with_capacity(self.len());
let mut source = self;
let expand = match tab_size {
2 => |s: &mut String, _: usize| s.push_str(" "),
4 => |s: &mut String, _: usize| s.push_str(" "),
8 => |s: &mut String, _: usize| s.push_str(" "),
_ => |s: &mut String, tab_size: usize| {
s.reserve(tab_size);
for _ in 0..tab_size {
s.push(' ');
}
},
};
while let Some(i) = source.find('\t') {
string.push_str(&source[..i]);
expand(&mut string, tab_size);
source = &source[i + 1..];
}
string.push_str(source);
string
}
fn truncate_to_chars(&self, count: usize) -> &str {
let end = self
.char_indices()
.map(|(index, _)| index)
.nth(count)
.unwrap_or(self.len());
&self[..end]
}
fn pad_start_to(&self, width: usize, fill: char) -> String {
let missing = width.saturating_sub(self.chars().count());
self.fill_start(fill, missing)
}
fn pad_end_to(&self, width: usize, fill: char) -> String {
let missing = width.saturating_sub(self.chars().count());
self.fill_end(fill, missing)
}
fn center_to(&self, width: usize, fill: char) -> String {
let missing = width.saturating_sub(self.chars().count());
if missing == 0 {
return self.to_string();
}
let left = missing / 2;
let right = missing - left;
self.fill_start(fill, left).fill_end(fill, right)
}
fn shift(&self, index: usize, count: usize, fill: impl EncodeUtf8) -> String {
assert!(self.is_char_boundary(index));
assert!(index <= self.len());
let mut buf = Default::default();
let fill = fill.encode_utf8(&mut buf);
if count == 0 || fill.is_empty() {
return self.to_string();
}
let mut s = self[..index].to_string();
for _ in 0..count {
s.push_str(fill);
}
s.push_str(&self[index..]);
s
}
fn levenshtein_distance(&self, other: &str) -> usize {
let (source, target) = (self, other);
if source.as_ptr() == target.as_ptr() && source.len() == target.len() {
return 0;
}
let mut end = source
.bytes()
.rev()
.zip(target.bytes().rev())
.take_while(|(l, r)| l == r)
.count();
while !source.is_char_boundary(source.len() - end) {
end -= 1;
}
let (source, target) = (&source[..source.len() - end], &target[..target.len() - end]);
let mut start = source
.bytes()
.zip(target.bytes())
.take_while(|(l, r)| l == r)
.count();
while !source.is_char_boundary(start) {
start -= 1;
}
let (source, target) = (&source[start..], &target[start..]);
if source.is_empty() {
return target.chars().count();
}
if target.is_empty() {
return source.chars().count();
}
let (source, target) = if source.len() < target.len() {
(target, source)
} else {
(source, target)
};
let target_len = target.chars().count();
let mut costs = (0..=target_len).collect::<Vec<_>>();
for (source_index, source_char) in source.chars().enumerate() {
let mut corner = source_index;
costs[0] = source_index + 1;
for (target_index, target_char) in target.chars().enumerate() {
let upper = costs[target_index + 1];
costs[target_index + 1] = if source_char == target_char {
corner
} else {
1 + usize::min(usize::min(costs[target_index], upper), corner)
};
corner = upper;
}
}
costs[target_len]
}
fn hamming_distance(&self, other: &str) -> Option<usize> {
let (mut source, mut target) = (self.chars(), other.chars());
let mut distance = 0;
loop {
let source_char = match source.next() {
Some(c) => c,
None => {
return match target.next() {
Some(_) => None,
None => Some(distance),
}
}
};
let target_char = target.next()?;
distance += (source_char != target_char) as usize;
}
}
fn common_prefix(&self, other: &str) -> &str {
let end = self
.char_indices()
.zip(other.chars())
.take_while(|((_, left), right)| left == right)
.last()
.map(|((index, left), _)| index + left.len_utf8())
.unwrap_or(0);
&self[..end]
}
fn common_suffix(&self, other: &str) -> &str {
let suffix_len = self
.chars()
.rev()
.zip(other.chars().rev())
.take_while(|(left, right)| left == right)
.fold(0, |acc, (c, _)| acc + c.len_utf8());
&self[self.len() - suffix_len..]
}
fn char_frequencies<M: sailed::FrequencyMap<char>>(&self) -> M {
let mut map = M::default();
self.chars().for_each(|c| map.increment(c));
map
}
fn byte_frequencies<M: sailed::FrequencyMap<u8>>(&self) -> M {
let mut map = M::default();
self.bytes().for_each(|c| map.increment(c));
map
}
fn longest_common_substring(&self, other: &str) -> &str {
if self.is_empty() || other.is_empty() {
return "";
}
let source = self.char_indices().collect::<Vec<_>>();
let target = other.chars().collect::<Vec<_>>();
let mut previous_row = vec![0; target.len() + 1];
let mut current_row = vec![0; target.len() + 1];
let mut best_len = 0;
let mut best_end = 0;
for (source_index, (_, source_char)) in source.iter().enumerate() {
for (target_index, target_char) in target.iter().enumerate() {
current_row[target_index + 1] = if source_char == target_char {
previous_row[target_index] + 1
} else {
0
};
if current_row[target_index + 1] > best_len {
best_len = current_row[target_index + 1];
best_end = source_index + 1;
}
}
previous_row.fill(0);
std::mem::swap(&mut previous_row, &mut current_row);
}
if best_len == 0 {
return "";
}
let start = source[best_end - best_len].0;
let end = source
.get(best_end)
.map(|(index, _)| *index)
.unwrap_or(self.len());
&self[start..end]
}
fn next_char_boundary(&self, mut index: usize) -> usize {
if index > self.len() {
return self.len();
}
while !self.is_char_boundary(index) {
index += 1;
}
index
}
fn previous_char_boundary(&self, mut index: usize) -> usize {
if index > self.len() {
return self.len();
}
while !self.is_char_boundary(index) {
index -= 1;
}
index
}
fn join<T: Display>(&self, iterable: impl IntoIterator<Item = T>) -> String {
let mut iter = iterable.into_iter();
let mut acc = String::new();
if let Some(value) = iter.next() {
write!(acc, "{value}").unwrap();
iter.try_for_each(|item| write!(acc, "{self}{item}"))
.unwrap();
}
acc
}
}
impl StrExt for String {
fn fill_start(&self, fill: impl EncodeUtf8, count: usize) -> String {
self.as_str().fill_start(fill, count)
}
fn fill_end(&self, fill: impl EncodeUtf8, count: usize) -> String {
self.as_str().fill_end(fill, count)
}
fn center(&self, fill: impl EncodeUtf8, count: usize) -> String {
self.as_str().center(fill, count)
}
fn enclose(&self, fill_start: impl EncodeUtf8, fill_end: impl EncodeUtf8) -> String {
self.as_str().enclose(fill_start, fill_end)
}
fn expand_tabs(&self, tab_size: usize) -> String {
self.as_str().expand_tabs(tab_size)
}
fn truncate_to_chars(&self, count: usize) -> &str {
self.as_str().truncate_to_chars(count)
}
fn pad_start_to(&self, width: usize, fill: char) -> String {
self.as_str().pad_start_to(width, fill)
}
fn pad_end_to(&self, width: usize, fill: char) -> String {
self.as_str().pad_end_to(width, fill)
}
fn center_to(&self, width: usize, fill: char) -> String {
self.as_str().center_to(width, fill)
}
fn shift(&self, index: usize, count: usize, fill: impl EncodeUtf8) -> String {
self.as_str().shift(index, count, fill)
}
fn levenshtein_distance(&self, other: &str) -> usize {
self.as_str().levenshtein_distance(other)
}
fn hamming_distance(&self, other: &str) -> Option<usize> {
self.as_str().hamming_distance(other)
}
fn common_prefix(&self, other: &str) -> &str {
self.as_str().common_prefix(other)
}
fn common_suffix(&self, other: &str) -> &str {
self.as_str().common_suffix(other)
}
fn char_frequencies<M: sailed::FrequencyMap<char>>(&self) -> M {
self.as_str().char_frequencies()
}
fn byte_frequencies<M: sailed::FrequencyMap<u8>>(&self) -> M {
self.as_str().byte_frequencies()
}
fn longest_common_substring(&self, other: &str) -> &str {
self.as_str().longest_common_substring(other)
}
fn next_char_boundary(&self, index: usize) -> usize {
self.as_str().next_char_boundary(index)
}
fn previous_char_boundary(&self, index: usize) -> usize {
self.as_str().previous_char_boundary(index)
}
fn join<T: Display>(&self, iterable: impl IntoIterator<Item = T>) -> String {
self.as_str().join(iterable)
}
}
pub trait StringExt: StrExt + sailed::StringExt {
fn trim_start_in_place(&mut self);
fn trim_end_in_place(&mut self);
fn trim_in_place(&mut self);
fn fill_start_in_place(&mut self, fill: impl EncodeUtf8, count: usize);
fn fill_end_in_place(&mut self, fill: impl EncodeUtf8, count: usize);
fn center_in_place(&mut self, fill: impl EncodeUtf8, count: usize);
fn enclose_in_place(&mut self, fill_start: impl EncodeUtf8, fill_end: impl EncodeUtf8);
fn expand_tabs_in_place(&mut self, tab_size: usize);
fn strip_prefix_in_place(&mut self, prefix: &str);
fn strip_suffix_in_place(&mut self, suffix: &str);
fn truncate_to_chars_in_place(&mut self, count: usize);
fn pad_start_to_in_place(&mut self, width: usize, fill: char);
fn pad_end_to_in_place(&mut self, width: usize, fill: char);
fn center_to_in_place(&mut self, width: usize, fill: char);
fn shift_in_place(&mut self, index: usize, count: usize, fill: impl EncodeUtf8);
fn replace_in_place(&mut self, from: impl EncodeUtf8, to: impl EncodeUtf8);
}
impl StringExt for String {
fn trim_start_in_place(&mut self) {
let trimmed = self.trim_start();
let start = unsafe { trimmed.as_ptr().offset_from(self.as_ptr()) as usize };
let len = trimmed.len();
unsafe { self.as_mut_vec().copy_within(start..start + len, 0) };
self.truncate(len);
}
fn trim_end_in_place(&mut self) {
self.truncate(self.trim_end().len());
}
fn trim_in_place(&mut self) {
let trimmed = self.trim();
let start = unsafe { trimmed.as_ptr().offset_from(self.as_ptr()) } as usize;
let len = trimmed.len();
unsafe { self.as_mut_vec().copy_within(start..start + len, 0) };
self.truncate(len);
}
fn fill_start_in_place(&mut self, fill: impl EncodeUtf8, count: usize) {
let mut buf = Default::default();
let fill = fill.encode_utf8(&mut buf);
if fill.is_empty() || count == 0 {
return;
}
#[allow(clippy::uninit_vec)]
unsafe {
let bytes = self.as_mut_vec();
let bytes_len = bytes.len();
let additional = fill.len() * count;
bytes.reserve(additional);
bytes.set_len(bytes_len + additional);
bytes.copy_within(0..bytes_len, additional);
for i in (0..fill.len() * count).step_by(fill.len().max(1)) {
bytes[i..i + fill.len()].copy_from_slice(fill.as_bytes());
}
}
}
fn fill_end_in_place(&mut self, fill: impl EncodeUtf8, count: usize) {
let mut buf = Default::default();
let fill = fill.encode_utf8(&mut buf);
if fill.is_empty() || count == 0 {
return;
}
self.reserve(fill.len() * count);
for _ in 0..count {
self.push_str(fill);
}
}
fn center_in_place(&mut self, fill: impl EncodeUtf8, count: usize) {
let mut buf = Default::default();
let fill = fill.encode_utf8(&mut buf);
if fill.is_empty() || count == 0 {
return;
}
#[allow(clippy::uninit_vec)]
unsafe {
let bytes = self.as_mut_vec();
let bytes_len = bytes.len();
let additional = fill.len() * count * 2;
bytes.reserve(additional);
bytes.set_len(bytes_len + additional);
bytes.copy_within(0..bytes_len, additional / 2);
for i in (0..count * fill.len()).step_by(fill.len()) {
bytes[i..i + fill.len()].copy_from_slice(fill.as_bytes());
}
for i in (bytes_len + additional / 2..bytes_len + additional).step_by(fill.len().max(1))
{
bytes[i..i + fill.len()].copy_from_slice(fill.as_bytes());
}
}
}
fn enclose_in_place(&mut self, fill_start: impl EncodeUtf8, fill_end: impl EncodeUtf8) {
let mut buf_start = Default::default();
let fill_start = fill_start.encode_utf8(&mut buf_start);
let mut buf_end = Default::default();
let fill_end = fill_end.encode_utf8(&mut buf_end);
if fill_start.is_empty() && fill_end.is_empty() {
return;
}
#[allow(clippy::uninit_vec)]
unsafe {
let bytes = self.as_mut_vec();
let bytes_len = bytes.len();
let additional = fill_start.len() + fill_end.len();
bytes.reserve(additional);
bytes.set_len(bytes_len + additional);
bytes.copy_within(0..bytes_len, fill_start.len());
bytes[..fill_start.len()].copy_from_slice(fill_start.as_bytes());
bytes[fill_start.len() + bytes_len..].copy_from_slice(fill_end.as_bytes());
}
}
fn expand_tabs_in_place(&mut self, tab_size: usize) {
if tab_size == 0 || self.is_empty() {
return;
}
let mut i = 0;
while i < self.len() {
if self[i..].starts_with('\t') {
unsafe { self.as_mut_vec()[i..i + 1].copy_from_slice(" ".as_bytes()) }
self.shift_in_place(i, tab_size.saturating_sub(1), ' ');
i += tab_size;
} else {
i = self.next_char_boundary(i + 1);
}
}
}
fn strip_prefix_in_place(&mut self, prefix: &str) {
if let Some(stripped) = self.strip_prefix(prefix) {
let start = self.len() - stripped.len();
let len = stripped.len();
unsafe { self.as_mut_vec().copy_within(start..start + len, 0) };
self.truncate(len);
}
}
fn strip_suffix_in_place(&mut self, suffix: &str) {
if let Some(stripped) = self.strip_suffix(suffix) {
self.truncate(stripped.len());
}
}
fn truncate_to_chars_in_place(&mut self, count: usize) {
let end = self
.char_indices()
.map(|(index, _)| index)
.nth(count)
.unwrap_or(self.len());
self.truncate(end);
}
fn pad_start_to_in_place(&mut self, width: usize, fill: char) {
let missing = width.saturating_sub(self.chars().count());
self.fill_start_in_place(fill, missing);
}
fn pad_end_to_in_place(&mut self, width: usize, fill: char) {
let missing = width.saturating_sub(self.chars().count());
self.fill_end_in_place(fill, missing);
}
fn center_to_in_place(&mut self, width: usize, fill: char) {
let missing = width.saturating_sub(self.chars().count());
if missing == 0 {
return;
}
let left = missing / 2;
let right = missing - left;
self.fill_start_in_place(fill, left);
self.fill_end_in_place(fill, right);
}
fn shift_in_place(&mut self, index: usize, count: usize, fill: impl EncodeUtf8) {
assert!(self.is_char_boundary(index));
assert!(index <= self.len());
let mut buf = Default::default();
let fill = EncodeUtf8::encode_utf8(&fill, &mut buf);
let additional = count * fill.len();
if count == 0 || fill.is_empty() {
return;
}
if count == 1 {
self.insert_str(index, fill);
return;
}
#[allow(clippy::uninit_vec)]
unsafe {
let bytes = self.as_mut_vec();
let bytes_len = bytes.len();
bytes.reserve(additional);
bytes.set_len(bytes_len + additional);
bytes.copy_within(index..bytes_len, index + count * fill.len());
for i in (index..index + count * fill.len()).step_by(fill.len()) {
bytes[i..i + fill.len()].copy_from_slice(fill.as_bytes())
}
}
}
fn replace_in_place(&mut self, from: impl EncodeUtf8, to: impl EncodeUtf8) {
let (mut from_buf, mut to_buf) = (Default::default(), Default::default());
let from = from.encode_utf8(&mut from_buf);
let to = to.encode_utf8(&mut to_buf);
if self.is_empty() || from.is_empty() {
return;
}
let mut offset = 0;
while let Some(i) = self[offset..].find(from) {
offset += i;
self.replace_range(offset..offset + from.len(), to);
offset += to.len();
}
}
}