#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct LeftStringWeight(Option<Vec<u8>>);
impl LeftStringWeight {
#[inline]
pub fn new(bytes: impl Into<Vec<u8>>) -> Self {
LeftStringWeight(Some(bytes.into()))
}
#[inline]
pub fn from_str(s: &str) -> Self {
LeftStringWeight(Some(s.as_bytes().to_vec()))
}
#[inline]
pub fn infinity() -> Self {
LeftStringWeight(None)
}
#[inline]
pub fn zero() -> Self {
Self::infinity()
}
#[inline]
pub fn epsilon() -> Self {
LeftStringWeight(Some(Vec::new()))
}
#[inline]
pub fn one() -> Self {
Self::epsilon()
}
#[inline]
pub fn is_infinite(&self) -> bool {
self.0.is_none()
}
#[inline]
pub fn is_zero(&self) -> bool {
self.is_infinite()
}
#[inline]
pub fn is_empty(&self) -> bool {
matches!(&self.0, Some(v) if v.is_empty())
}
#[inline]
pub fn is_one(&self) -> bool {
self.is_empty()
}
#[inline]
pub fn as_bytes(&self) -> Option<&[u8]> {
self.0.as_deref()
}
pub fn as_str(&self) -> Option<&str> {
self.0
.as_ref()
.and_then(|bytes| std::str::from_utf8(bytes).ok())
}
#[inline]
pub fn len(&self) -> Option<usize> {
self.0.as_ref().map(|v| v.len())
}
pub fn longest_common_prefix(a: &[u8], b: &[u8]) -> Vec<u8> {
let mut prefix = Vec::with_capacity(a.len().min(b.len()));
for (&x, &y) in a.iter().zip(b.iter()) {
if x == y {
prefix.push(x);
} else {
break;
}
}
prefix
}
pub fn plus(&self, other: &Self) -> Self {
match (&self.0, &other.0) {
(None, _) => other.clone(),
(_, None) => self.clone(),
(Some(a), Some(b)) => LeftStringWeight(Some(Self::longest_common_prefix(a, b))),
}
}
pub fn times(&self, other: &Self) -> Self {
match (&self.0, &other.0) {
(None, _) | (_, None) => LeftStringWeight::infinity(),
(Some(a), Some(b)) => {
let mut result = a.clone();
result.extend_from_slice(b);
LeftStringWeight(Some(result))
}
}
}
pub fn star(&self) -> Self {
Self::one()
}
pub fn approx_eq(&self, other: &Self, _epsilon: f64) -> bool {
self == other
}
pub fn natural_less(&self, other: &Self) -> Option<bool> {
match (&self.0, &other.0) {
(None, None) => Some(false),
(None, Some(_)) => Some(false), (Some(_), None) => Some(true), (Some(a), Some(b)) => Some(a.len() < b.len()),
}
}
pub fn to_bytes(&self) -> Vec<u8> {
match &self.0 {
None => vec![0xFF], Some(bytes) => {
let mut result = vec![0x00]; result.extend(bytes);
result
}
}
}
}
impl Default for LeftStringWeight {
#[inline]
fn default() -> Self {
Self::one()
}
}
impl From<&str> for LeftStringWeight {
fn from(s: &str) -> Self {
LeftStringWeight::from_str(s)
}
}
impl From<String> for LeftStringWeight {
fn from(s: String) -> Self {
LeftStringWeight(Some(s.into_bytes()))
}
}
impl From<Vec<u8>> for LeftStringWeight {
fn from(bytes: Vec<u8>) -> Self {
LeftStringWeight(Some(bytes))
}
}
impl std::ops::Add for LeftStringWeight {
type Output = Self;
fn add(self, other: Self) -> Self {
self.plus(&other)
}
}
impl std::ops::Add<&LeftStringWeight> for LeftStringWeight {
type Output = Self;
fn add(self, other: &Self) -> Self {
self.plus(other)
}
}
impl std::ops::Mul for LeftStringWeight {
type Output = Self;
fn mul(self, other: Self) -> Self {
self.times(&other)
}
}
impl std::ops::Mul<&LeftStringWeight> for LeftStringWeight {
type Output = Self;
fn mul(self, other: &Self) -> Self {
self.times(other)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct RightStringWeight(Option<Vec<u8>>);
impl RightStringWeight {
#[inline]
pub fn new(bytes: impl Into<Vec<u8>>) -> Self {
RightStringWeight(Some(bytes.into()))
}
#[inline]
pub fn from_str(s: &str) -> Self {
RightStringWeight(Some(s.as_bytes().to_vec()))
}
#[inline]
pub fn infinity() -> Self {
RightStringWeight(None)
}
#[inline]
pub fn zero() -> Self {
Self::infinity()
}
#[inline]
pub fn epsilon() -> Self {
RightStringWeight(Some(Vec::new()))
}
#[inline]
pub fn one() -> Self {
Self::epsilon()
}
#[inline]
pub fn is_infinite(&self) -> bool {
self.0.is_none()
}
#[inline]
pub fn is_zero(&self) -> bool {
self.is_infinite()
}
#[inline]
pub fn is_empty(&self) -> bool {
matches!(&self.0, Some(v) if v.is_empty())
}
#[inline]
pub fn is_one(&self) -> bool {
self.is_empty()
}
#[inline]
pub fn as_bytes(&self) -> Option<&[u8]> {
self.0.as_deref()
}
pub fn as_str(&self) -> Option<&str> {
self.0
.as_ref()
.and_then(|bytes| std::str::from_utf8(bytes).ok())
}
#[inline]
pub fn len(&self) -> Option<usize> {
self.0.as_ref().map(|v| v.len())
}
pub fn longest_common_suffix(a: &[u8], b: &[u8]) -> Vec<u8> {
let mut suffix = Vec::with_capacity(a.len().min(b.len()));
for (&x, &y) in a.iter().rev().zip(b.iter().rev()) {
if x == y {
suffix.push(x);
} else {
break;
}
}
suffix.reverse();
suffix
}
pub fn plus(&self, other: &Self) -> Self {
match (&self.0, &other.0) {
(None, _) => other.clone(),
(_, None) => self.clone(),
(Some(a), Some(b)) => RightStringWeight(Some(Self::longest_common_suffix(a, b))),
}
}
pub fn times(&self, other: &Self) -> Self {
match (&self.0, &other.0) {
(None, _) | (_, None) => RightStringWeight::infinity(),
(Some(a), Some(b)) => {
let mut result = a.clone();
result.extend_from_slice(b);
RightStringWeight(Some(result))
}
}
}
pub fn star(&self) -> Self {
Self::one()
}
pub fn approx_eq(&self, other: &Self, _epsilon: f64) -> bool {
self == other
}
pub fn natural_less(&self, other: &Self) -> Option<bool> {
match (&self.0, &other.0) {
(None, None) => Some(false),
(None, Some(_)) => Some(false),
(Some(_), None) => Some(true),
(Some(a), Some(b)) => Some(a.len() < b.len()),
}
}
pub fn to_bytes(&self) -> Vec<u8> {
match &self.0 {
None => vec![0xFF],
Some(bytes) => {
let mut result = vec![0x00];
result.extend(bytes);
result
}
}
}
}
impl Default for RightStringWeight {
#[inline]
fn default() -> Self {
Self::one()
}
}
impl From<&str> for RightStringWeight {
fn from(s: &str) -> Self {
RightStringWeight::from_str(s)
}
}
impl From<String> for RightStringWeight {
fn from(s: String) -> Self {
RightStringWeight(Some(s.into_bytes()))
}
}
impl From<Vec<u8>> for RightStringWeight {
fn from(bytes: Vec<u8>) -> Self {
RightStringWeight(Some(bytes))
}
}
impl std::ops::Add for RightStringWeight {
type Output = Self;
fn add(self, other: Self) -> Self {
self.plus(&other)
}
}
impl std::ops::Add<&RightStringWeight> for RightStringWeight {
type Output = Self;
fn add(self, other: &Self) -> Self {
self.plus(other)
}
}
impl std::ops::Mul for RightStringWeight {
type Output = Self;
fn mul(self, other: Self) -> Self {
self.times(&other)
}
}
impl std::ops::Mul<&RightStringWeight> for RightStringWeight {
type Output = Self;
fn mul(self, other: &Self) -> Self {
self.times(other)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_left_basic_operations() {
let abc = LeftStringWeight::from_str("abc");
let abx = LeftStringWeight::from_str("abx");
let def = LeftStringWeight::from_str("def");
let lcp = abc.plus(&abx);
assert_eq!(lcp.as_str(), Some("ab"));
let lcp2 = abc.plus(&def);
assert_eq!(lcp2.as_str(), Some(""));
let concat = abc.times(&def);
assert_eq!(concat.as_str(), Some("abcdef"));
}
#[test]
fn test_left_identities() {
let abc = LeftStringWeight::from_str("abc");
let sum = abc.plus(&LeftStringWeight::zero());
assert_eq!(sum, abc);
let sum2 = LeftStringWeight::zero().plus(&abc);
assert_eq!(sum2, abc);
let prod = abc.times(&LeftStringWeight::one());
assert_eq!(prod, abc);
let prod2 = LeftStringWeight::one().times(&abc);
assert_eq!(prod2, abc);
}
#[test]
fn test_left_annihilation() {
let abc = LeftStringWeight::from_str("abc");
let prod = abc.times(&LeftStringWeight::zero());
assert!(prod.is_zero());
let prod2 = LeftStringWeight::zero().times(&abc);
assert!(prod2.is_zero());
}
#[test]
fn test_left_commutativity() {
let abc = LeftStringWeight::from_str("abc");
let abx = LeftStringWeight::from_str("abx");
assert_eq!(abc.plus(&abx), abx.plus(&abc));
}
#[test]
fn test_left_associativity() {
let ab = LeftStringWeight::from_str("ab");
let abc = LeftStringWeight::from_str("abc");
let abcd = LeftStringWeight::from_str("abcd");
let left = ab.plus(&abc).plus(&abcd);
let right = ab.plus(&abc.plus(&abcd));
assert_eq!(left, right);
let a = LeftStringWeight::from_str("a");
let b = LeftStringWeight::from_str("b");
let c = LeftStringWeight::from_str("c");
let left = a.times(&b).times(&c);
let right = a.times(&b.times(&c));
assert_eq!(left, right);
assert_eq!(left.as_str(), Some("abc"));
}
#[test]
fn test_left_distributivity() {
let a = LeftStringWeight::from_str("x");
let b = LeftStringWeight::from_str("ab");
let c = LeftStringWeight::from_str("ac");
let left = a.times(&b.plus(&c));
let right = a.times(&b).plus(&a.times(&c));
assert_eq!(left, right);
}
#[test]
fn test_left_star() {
let abc = LeftStringWeight::from_str("abc");
let eps = LeftStringWeight::epsilon();
assert_eq!(eps.star(), LeftStringWeight::one());
assert_eq!(abc.star(), LeftStringWeight::one());
}
#[test]
fn test_right_basic_operations() {
let abc = RightStringWeight::from_str("abc");
let xbc = RightStringWeight::from_str("xbc");
let def = RightStringWeight::from_str("def");
let lcs = abc.plus(&xbc);
assert_eq!(lcs.as_str(), Some("bc"));
let lcs2 = abc.plus(&def);
assert_eq!(lcs2.as_str(), Some(""));
let concat = abc.times(&def);
assert_eq!(concat.as_str(), Some("abcdef"));
}
#[test]
fn test_right_identities() {
let abc = RightStringWeight::from_str("abc");
let sum = abc.plus(&RightStringWeight::zero());
assert_eq!(sum, abc);
let prod = abc.times(&RightStringWeight::one());
assert_eq!(prod, abc);
}
#[test]
fn test_right_distributivity() {
let a = RightStringWeight::from_str("ab");
let b = RightStringWeight::from_str("cb");
let c = RightStringWeight::from_str("x");
let left = a.plus(&b).times(&c);
let right = a.times(&c).plus(&b.times(&c));
assert_eq!(left, right);
}
#[test]
fn test_right_star() {
let abc = RightStringWeight::from_str("abc");
assert_eq!(abc.star(), RightStringWeight::one());
}
#[test]
fn test_empty_string_lcp() {
let empty = LeftStringWeight::epsilon();
let abc = LeftStringWeight::from_str("abc");
assert_eq!(empty.plus(&abc), LeftStringWeight::epsilon());
}
#[test]
fn test_empty_string_lcs() {
let empty = RightStringWeight::epsilon();
let abc = RightStringWeight::from_str("abc");
assert_eq!(empty.plus(&abc), RightStringWeight::epsilon());
}
#[test]
fn test_bytes_conversion() {
let bytes = vec![0x48, 0x65, 0x6c, 0x6c, 0x6f]; let left = LeftStringWeight::new(bytes.clone());
let right = RightStringWeight::new(bytes.clone());
assert_eq!(left.as_bytes(), Some(bytes.as_slice()));
assert_eq!(left.as_str(), Some("Hello"));
assert_eq!(right.as_bytes(), Some(bytes.as_slice()));
assert_eq!(right.as_str(), Some("Hello"));
}
#[test]
fn test_non_utf8_bytes() {
let bytes = vec![0xFF, 0xFE]; let left = LeftStringWeight::new(bytes.clone());
assert_eq!(left.as_bytes(), Some(bytes.as_slice()));
assert_eq!(left.as_str(), None); }
#[test]
fn test_longest_common_prefix_function() {
assert_eq!(
LeftStringWeight::longest_common_prefix(b"abc", b"abx"),
b"ab".to_vec()
);
assert_eq!(
LeftStringWeight::longest_common_prefix(b"abc", b"abc"),
b"abc".to_vec()
);
assert_eq!(
LeftStringWeight::longest_common_prefix(b"abc", b"xyz"),
b"".to_vec()
);
assert_eq!(
LeftStringWeight::longest_common_prefix(b"", b"abc"),
b"".to_vec()
);
}
#[test]
fn test_longest_common_suffix_function() {
assert_eq!(
RightStringWeight::longest_common_suffix(b"abc", b"xbc"),
b"bc".to_vec()
);
assert_eq!(
RightStringWeight::longest_common_suffix(b"abc", b"abc"),
b"abc".to_vec()
);
assert_eq!(
RightStringWeight::longest_common_suffix(b"abc", b"xyz"),
b"".to_vec()
);
assert_eq!(
RightStringWeight::longest_common_suffix(b"", b"abc"),
b"".to_vec()
);
}
#[test]
fn test_operator_overloading() {
let abc = LeftStringWeight::from_str("abc");
let abx = LeftStringWeight::from_str("abx");
let def = LeftStringWeight::from_str("def");
let lcp = abc.clone() + abx.clone();
assert_eq!(lcp.as_str(), Some("ab"));
let concat = abc.clone() * def.clone();
assert_eq!(concat.as_str(), Some("abcdef"));
let lcp_ref = abc.clone() + &abx;
assert_eq!(lcp_ref.as_str(), Some("ab"));
let concat_ref = abc.clone() * &def;
assert_eq!(concat_ref.as_str(), Some("abcdef"));
}
}