Skip to content

Commit

Permalink
perf: tweak inline annotations
Browse files Browse the repository at this point in the history
This replaces `inline(always)` annotations with `inline` (except for one
case, in which we add a comment).

Notably, inlining the methods on `Bound` appear to provide a nice boost:

    group                           c01                    c02
    -----                           ---                    ---
    search/wikiurls/fst/contains    1.06    428.7±9.53ns   1.00    404.8±4.58ns
    search/words/fst/contains       1.05    199.8±1.74ns   1.00    191.0±3.34ns
  • Loading branch information
BurntSushi committed Mar 7, 2020
1 parent 826978c commit e8db372
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 52 deletions.
10 changes: 10 additions & 0 deletions src/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,21 @@ use std::io;

/// Read a u32 in little endian format from the beginning of the given slice.
/// This panics if the slice has length less than 4.
#[inline]
pub fn read_u32_le(slice: &[u8]) -> u32 {
u32::from_le_bytes(slice[..4].try_into().unwrap())
}

/// Read a u64 in little endian format from the beginning of the given slice.
/// This panics if the slice has length less than 8.
#[inline]
pub fn read_u64_le(slice: &[u8]) -> u64 {
u64::from_le_bytes(slice[..8].try_into().unwrap())
}

/// Write a u32 in little endian format to the beginning of the given slice.
/// This panics if the slice has length less than 4.
#[inline]
pub fn write_u32_le(n: u32, slice: &mut [u8]) {
assert!(slice.len() >= 4);
let bytes = n.to_le_bytes();
Expand All @@ -26,6 +29,7 @@ pub fn write_u32_le(n: u32, slice: &mut [u8]) {

/// Like write_u32_le, but to an io::Write implementation. If every byte could
/// not be writen, then this returns an error.
#[inline]
pub fn io_write_u32_le<W: io::Write>(n: u32, mut wtr: W) -> io::Result<()> {
let mut buf = [0; 4];
write_u32_le(n, &mut buf);
Expand All @@ -34,6 +38,7 @@ pub fn io_write_u32_le<W: io::Write>(n: u32, mut wtr: W) -> io::Result<()> {

/// Write a u64 in little endian format to the beginning of the given slice.
/// This panics if the slice has length less than 8.
#[inline]
pub fn write_u64_le(n: u64, slice: &mut [u8]) {
assert!(slice.len() >= 8);
let bytes = n.to_le_bytes();
Expand All @@ -49,6 +54,7 @@ pub fn write_u64_le(n: u64, slice: &mut [u8]) {

/// Like write_u64_le, but to an io::Write implementation. If every byte could
/// not be writen, then this returns an error.
#[inline]
pub fn io_write_u64_le<W: io::Write>(n: u64, mut wtr: W) -> io::Result<()> {
let mut buf = [0; 8];
write_u64_le(n, &mut buf);
Expand All @@ -58,6 +64,7 @@ pub fn io_write_u64_le<W: io::Write>(n: u64, mut wtr: W) -> io::Result<()> {
/// pack_uint packs the given integer in the smallest number of bytes possible,
/// and writes it to the given writer. The number of bytes written is returned
/// on success.
#[inline]
pub fn pack_uint<W: io::Write>(wtr: W, n: u64) -> io::Result<u8> {
let nbytes = pack_size(n);
pack_uint_in(wtr, n, nbytes).map(|_| nbytes)
Expand All @@ -68,6 +75,7 @@ pub fn pack_uint<W: io::Write>(wtr: W, n: u64) -> io::Result<u8> {
///
/// `nbytes` must be >= pack_size(n) and <= 8, where `pack_size(n)` is the
/// smallest number of bytes that can store the integer given.
#[inline]
pub fn pack_uint_in<W: io::Write>(
mut wtr: W,
mut n: u64,
Expand All @@ -87,6 +95,7 @@ pub fn pack_uint_in<W: io::Write>(
/// position in `slice` after reading `nbytes` bytes.
///
/// `nbytes` must be >= 1 and <= 8.
#[inline]
pub fn unpack_uint(slice: &[u8], nbytes: u8) -> u64 {
assert!(1 <= nbytes && nbytes <= 8);

Expand All @@ -98,6 +107,7 @@ pub fn unpack_uint(slice: &[u8], nbytes: u8) -> u64 {
}

/// pack_size returns the smallest number of bytes that can encode `n`.
#[inline]
pub fn pack_size(n: u64) -> u8 {
if n < 1 << 8 {
1
Expand Down
18 changes: 17 additions & 1 deletion src/raw/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ impl<D: AsRef<[u8]>> Fst<D> {
}

/// Returns the root node of this fst.
#[inline(always)]
#[inline]
pub fn root(&self) -> Node<'_> {
self.as_ref().root()
}
Expand Down Expand Up @@ -632,6 +632,7 @@ struct FstRef<'f> {
}

impl<'f> FstRef<'f> {
#[inline]
fn get(&self, key: &[u8]) -> Option<Output> {
let mut node = self.root();
let mut out = Output::zero();
Expand All @@ -652,6 +653,7 @@ impl<'f> FstRef<'f> {
}
}

#[inline]
fn contains_key(&self, key: &[u8]) -> bool {
let mut node = self.root();
for &b in key {
Expand All @@ -663,6 +665,7 @@ impl<'f> FstRef<'f> {
node.is_final()
}

#[inline]
fn get_key_into(&self, mut value: u64, key: &mut Vec<u8>) -> bool {
let mut node = self.root();
while value != 0 || !node.is_final() {
Expand All @@ -682,42 +685,52 @@ impl<'f> FstRef<'f> {
true
}

#[inline]
fn len(&self) -> usize {
self.meta.len
}

#[inline]
fn is_empty(&self) -> bool {
self.meta.len == 0
}

#[inline]
fn size(&self) -> usize {
self.as_bytes().len()
}

#[inline]
fn fst_type(&self) -> FstType {
self.meta.ty
}

#[inline]
fn root_addr(&self) -> CompiledAddr {
self.meta.root_addr
}

#[inline]
fn root(&self) -> Node<'f> {
self.node(self.root_addr())
}

#[inline]
fn node(&self, addr: CompiledAddr) -> Node<'f> {
Node::new(self.meta.version, addr, self.as_bytes())
}

#[inline]
fn to_vec(&self) -> Vec<u8> {
self.as_bytes().to_vec()
}

#[inline]
fn as_bytes(&self) -> &'f [u8] {
self.data
}

#[inline]
fn empty_final_output(&self) -> Option<Output> {
let root = self.root();
if root.is_final() {
Expand Down Expand Up @@ -883,6 +896,7 @@ enum Bound {
}

impl Bound {
#[inline]
fn exceeded_by(&self, inp: &[u8]) -> bool {
match *self {
Bound::Included(ref v) => inp > v,
Expand All @@ -891,6 +905,7 @@ impl Bound {
}
}

#[inline]
fn is_empty(&self) -> bool {
match *self {
Bound::Included(ref v) => v.is_empty(),
Expand All @@ -899,6 +914,7 @@ impl Bound {
}
}

#[inline]
fn is_inclusive(&self) -> bool {
match *self {
Bound::Excluded(_) => false,
Expand Down
Loading

0 comments on commit e8db372

Please sign in to comment.