为什么这些ASCII方法不一致?

时间:2014-12-16 07:12:39

标签: ascii rust

当我查看rust ASCII operations时,感觉

之间存在一致性问题

is_lowercase / is_uppercase:

pub fn is_uppercase(&self) -> bool {
    (self.chr - b'A') < 26
}

is_alphabetic:

pub fn is_alphabetic(&self) -> bool {
    (self.chr >= 0x41 && self.chr <= 0x5A) || (self.chr >= 0x61 && self.chr <= 0x7A)
}

有充分的理由吗?这两种方法完全相同还是我遗漏了什么? 所有这些功能都标记为稳定,所以我很困惑。

编辑:

为了更清楚,我期望的是决定最佳(在性能/可读性/通用实践方面)实现更低/更高的

pub fn is_alphabetic(&self) -> bool {
    self.is_lowercase() || self.is_uppercase()
}

3 个答案:

答案 0 :(得分:0)

他们是等同的。 is_alphabetic可以使用字节文字而不是十六进制代码编写,使其更具可读性并与其他函数匹配:

pub fn is_alphabetic(&self) -> bool {
    (self.chr >= b'A' && self.chr <= b'Z') ||
    (self.chr >= b'a' && self.chr <= b'z')
}

答案 1 :(得分:0)

is_alphabetic中的值肯定对应于字母的相应ASCII值。您可以使用以下方式验证:

println!("0x{:x} 0x{:x}", b'A', b'A');
println!("0x{:x} 0x{:x}", b'a', b'z');

is_alphabetic依赖于ASCII小写和大写字母是连续的(不幸的是,彼此之间没有)。它可以写成:

pub fn is_alphabetic(&self) -> bool {
  (self.chr >= b'A' && self.chr <= b'Z') || (self.chr >= b'a' && self.chr <= b'z')
}

// Or
pub fn is_alphabetic(&self) -> bool {
  self.is_upper() || self.is_lower()
}

is_loweris_upper都依赖无符号数学下溢才是正确的。如果a0x61z0x7A,并且我们从两者中减去a,则会得到025。但是,如果它比a少一个,我们会得到0xFF0xFF不是< 26,因此检查失败。

答案 2 :(得分:0)

由于问题改为关于性能,我将添加第二个答案。

首先,我创建了一个Ascii模块的克隆(playpen):

pub struct Alpha(u8);

impl Alpha {
    #[inline(never)]
    pub fn is_uppercase_sub(&self) -> bool {
        (self.0 - b'A') < 26
    }

    #[inline(never)]
    pub fn is_uppercase_range(&self) -> bool {
        self.0 >= 0x41 && self.0 <= 0x5A
    }
}

fn main() {
    let yes = Alpha(b'A');
    let no  = Alpha(b'a');

    println!("{}, {}", yes.is_uppercase_sub(), yes.is_uppercase_range());
}

在游戏围栏中,确保优化设置为-O2,然后点击IR。这显示了LLVM I 中间 R 表示。如果您愿意,它就像一个更高级别的装配。

有很多输出,但查找fastcc的部分。我删除了各种位以使这段代码更清晰,但你可以看到完全相同的函数被调用,即使我们的代码调用了两个不同的实现,一个带有减法,另一个带有一个范围:

%3 = call fastcc zeroext i1 @_ZN5Alpha16is_uppercase_sub20h63aa0b11479803f4laaE
%5 = call fastcc zeroext i1 @_ZN5Alpha16is_uppercase_sub20h63aa0b11479803f4laaE

LLVM优化器可以告诉这些实现是相同的,所以真的取决于开发人员的偏好。如果你愿意的话,你可能能够提交Rust以使它们保持一致! ^ _ ^

询问is_alphabetic更难;内联将在这里发挥作用。 如果 LLVM将is_upperis_lower内联到is_alphabetic,那么您建议的更改会更好。 如果没有,那么可能是1个函数调用现在是 3 可能非常糟糕。

这一类问题在这个层面上难以回答;一个人必须在大型的真实Rust代码中查看(编辑和分析!)才能理解优化器的内联。