use super::functions::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct Span {
pub start: BytePos,
pub end: BytePos,
}
impl Span {
pub fn new(start: BytePos, end: BytePos) -> Self {
Self { start, end }
}
pub fn from_offsets(start: u32, end: u32) -> Self {
Self {
start: BytePos(start),
end: BytePos(end),
}
}
pub fn point(pos: BytePos) -> Self {
Self {
start: pos,
end: pos,
}
}
pub fn len(self) -> u32 {
self.end.0.saturating_sub(self.start.0)
}
pub fn is_empty(self) -> bool {
self.start >= self.end
}
pub fn merge(self, other: Span) -> Span {
Span {
start: BytePos(self.start.0.min(other.start.0)),
end: BytePos(self.end.0.max(other.end.0)),
}
}
pub fn contains(self, pos: BytePos) -> bool {
self.start <= pos && pos < self.end
}
pub fn slice<'a>(&self, src: &'a str) -> Option<&'a str> {
let s = self.start.to_usize();
let e = self.end.to_usize();
src.get(s..e)
}
pub fn shift(self, n: u32) -> Self {
Span {
start: self.start.shift(n),
end: self.end.shift(n),
}
}
}
#[allow(dead_code)]
pub struct StringEncoderExt {
pub encoding: String,
}
impl StringEncoderExt {
pub fn utf8() -> Self {
Self {
encoding: "UTF-8".to_string(),
}
}
pub fn encode(&self, s: &str) -> Vec<u8> {
s.as_bytes().to_vec()
}
pub fn decode(&self, bytes: &[u8]) -> Result<String, std::string::FromUtf8Error> {
String::from_utf8(bytes.to_vec())
}
pub fn roundtrip(&self, s: &str) -> bool {
self.decode(&self.encode(s)).as_deref() == Ok(s)
}
}
#[allow(dead_code)]
pub struct StringMonoidExt {
pub buffer: String,
}
impl StringMonoidExt {
pub fn new() -> Self {
Self {
buffer: String::new(),
}
}
pub fn mappend(&mut self, other: &str) {
self.buffer.push_str(other);
}
pub fn is_identity(&self) -> bool {
self.buffer.is_empty()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct LineCol {
pub line: u32,
pub col: u32,
}
impl LineCol {
pub fn new(line: u32, col: u32) -> Self {
Self { line, col }
}
}
#[allow(dead_code)]
pub struct SubstringFinder2 {
pub text: String,
pub pattern: String,
}
impl SubstringFinder2 {
pub fn new(text: impl Into<String>, pattern: impl Into<String>) -> Self {
Self {
text: text.into(),
pattern: pattern.into(),
}
}
pub fn find_all(&self) -> Vec<usize> {
let mut positions = Vec::new();
let t = &self.text;
let p = &self.pattern;
if p.is_empty() {
return positions;
}
let mut start = 0;
while let Some(pos) = t[start..].find(p.as_str()) {
positions.push(start + pos);
start += pos + p.len();
}
positions
}
pub fn find_kmp(&self) -> Vec<usize> {
str_ext2_kmp_search(&self.text, &self.pattern)
}
}
#[allow(dead_code)]
pub struct LevenshteinMetric2 {
pub max_dist: Option<usize>,
}
impl LevenshteinMetric2 {
pub fn new() -> Self {
Self { max_dist: None }
}
pub fn with_max(d: usize) -> Self {
Self { max_dist: Some(d) }
}
pub fn distance(&self, a: &str, b: &str) -> usize {
str_ext2_levenshtein(a, b)
}
pub fn within_threshold(&self, a: &str, b: &str) -> bool {
match self.max_dist {
Some(d) => self.distance(a, b) <= d,
None => true,
}
}
pub fn identity_law(&self, a: &str) -> bool {
self.distance(a, a) == 0
}
pub fn symmetry_law(&self, a: &str, b: &str) -> bool {
self.distance(a, b) == self.distance(b, a)
}
}
#[derive(Debug, Default, Clone)]
pub struct StringBuilder {
pub(super) buf: String,
pub(super) indent_level: usize,
indent_width: usize,
}
impl StringBuilder {
pub fn new() -> Self {
Self {
buf: String::new(),
indent_level: 0,
indent_width: 2,
}
}
pub fn with_capacity(cap: usize) -> Self {
Self {
buf: String::with_capacity(cap),
indent_level: 0,
indent_width: 2,
}
}
pub fn set_indent_width(&mut self, w: usize) -> &mut Self {
self.indent_width = w;
self
}
pub fn push_str(&mut self, s: &str) -> &mut Self {
self.buf.push_str(s);
self
}
pub fn push(&mut self, c: char) -> &mut Self {
self.buf.push(c);
self
}
pub fn newline(&mut self) -> &mut Self {
self.buf.push('\n');
self.buf
.push_str(&" ".repeat(self.indent_level * self.indent_width));
self
}
pub fn line(&mut self, s: &str) -> &mut Self {
self.buf.push_str(s);
self.newline();
self
}
pub fn indent(&mut self) -> &mut Self {
self.indent_level += 1;
self
}
pub fn dedent(&mut self) -> &mut Self {
self.indent_level = self.indent_level.saturating_sub(1);
self
}
pub fn push_fmt(&mut self, args: std::fmt::Arguments<'_>) -> &mut Self {
use std::fmt::Write;
let _ = self.buf.write_fmt(args);
self
}
pub fn len(&self) -> usize {
self.buf.len()
}
pub fn is_empty(&self) -> bool {
self.buf.is_empty()
}
pub fn finish(self) -> String {
self.buf
}
pub fn as_str(&self) -> &str {
&self.buf
}
pub fn clear(&mut self) {
self.buf.clear();
}
pub fn sep(&mut self, s: &str) -> &mut Self {
if !self.buf.is_empty() {
self.buf.push_str(s);
}
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct BytePos(pub u32);
impl BytePos {
pub fn from_usize(n: usize) -> Self {
Self(n as u32)
}
pub fn to_usize(self) -> usize {
self.0 as usize
}
pub fn shift(self, n: u32) -> Self {
Self(self.0 + n)
}
}
#[allow(dead_code)]
pub struct RollingHashExt {
pub base: u64,
pub modulus: u64,
}
impl RollingHashExt {
pub fn new() -> Self {
Self {
base: 31,
modulus: 1_000_000_007,
}
}
pub fn hash_str(&self, s: &str) -> u64 {
s.bytes().fold(0u64, |acc, b| {
(acc.wrapping_mul(self.base).wrapping_add(b as u64)) % self.modulus
})
}
pub fn find(&self, text: &str, pattern: &str) -> Vec<usize> {
str_ext2_rabin_karp(text, pattern, self.base, self.modulus)
}
}